mirror of
https://github.com/cheveguerra/whatsapp-web.js.git
synced 2026-04-20 04:29:15 +00:00
Merge branch 'main' into patch-participants
This commit is contained in:
1
.github/workflows/lint.yml
vendored
1
.github/workflows/lint.yml
vendored
@@ -2,7 +2,6 @@ name: Lint
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
eslint:
|
eslint:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[](https://www.npmjs.com/package/whatsapp-web.js) [](https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765)  [](https://discord.gg/H7DqQs4)
|
[](https://www.npmjs.com/package/whatsapp-web.js) [](https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765)  [](https://discord.gg/H7DqQs4)
|
||||||
|
|
||||||
# whatsapp-web.js
|
# whatsapp-web.js
|
||||||
A WhatsApp API client that connects through the WhatsApp Web browser app
|
A WhatsApp API client that connects through the WhatsApp Web browser app
|
||||||
|
|||||||
1
index.d.ts
vendored
1
index.d.ts
vendored
@@ -443,6 +443,7 @@ declare namespace WAWebJS {
|
|||||||
PAYMENT = 'payment',
|
PAYMENT = 'payment',
|
||||||
UNKNOWN = 'unknown',
|
UNKNOWN = 'unknown',
|
||||||
GROUP_INVITE = 'groups_v4_invite',
|
GROUP_INVITE = 'groups_v4_invite',
|
||||||
|
BUTTONS_RESPONSE = 'buttons_response'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Client status */
|
/** Client status */
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
"main": "./index.js",
|
"main": "./index.js",
|
||||||
"typings": "./index.d.ts",
|
"typings": "./index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha tests",
|
"test": "mocha tests --recursive",
|
||||||
|
"test-single": "mocha",
|
||||||
"shell": "node --experimental-repl-await ./shell.js",
|
"shell": "node --experimental-repl-await ./shell.js",
|
||||||
"generate-docs": "node_modules/.bin/jsdoc --configure .jsdoc.json --verbose"
|
"generate-docs": "node_modules/.bin/jsdoc --configure .jsdoc.json --verbose"
|
||||||
},
|
},
|
||||||
@@ -40,13 +41,13 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node-fetch": "^2.5.12",
|
"@types/node-fetch": "^2.5.12",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"eslint": "^8.4.1",
|
"eslint": "^8.4.1",
|
||||||
"eslint-plugin-mocha": "^9.0.0",
|
"eslint-plugin-mocha": "^10.0.3",
|
||||||
"jsdoc": "^3.6.4",
|
"jsdoc": "^3.6.4",
|
||||||
"jsdoc-baseline": "^0.1.5",
|
"jsdoc-baseline": "^0.1.5",
|
||||||
"mocha": "^9.0.2",
|
"mocha": "^9.0.2",
|
||||||
"sinon": "^12.0.1"
|
"sinon": "^13.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class Client extends EventEmitter {
|
|||||||
page = (await browser.pages())[0];
|
page = (await browser.pages())[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
page.setUserAgent(this.options.userAgent);
|
await page.setUserAgent(this.options.userAgent);
|
||||||
|
|
||||||
this.pupBrowser = browser;
|
this.pupBrowser = browser;
|
||||||
this.pupPage = page;
|
this.pupPage = page;
|
||||||
@@ -109,7 +109,7 @@ class Client extends EventEmitter {
|
|||||||
const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '[data-icon="intro-md-beta-logo-dark"], [data-icon="intro-md-beta-logo-light"], [data-asset-intro-image-light="true"], [data-asset-intro-image-dark="true"]';
|
const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '[data-icon="intro-md-beta-logo-dark"], [data-icon="intro-md-beta-logo-light"], [data-asset-intro-image-light="true"], [data-asset-intro-image-dark="true"]';
|
||||||
|
|
||||||
if (this.options.session) {
|
if (this.options.session) {
|
||||||
// Check if session restore was successfull
|
// Check if session restore was successful
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: this.options.authTimeoutMs });
|
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: this.options.authTimeoutMs });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -168,10 +168,22 @@ class Client extends EventEmitter {
|
|||||||
this._qrRefreshInterval = setInterval(getQrCode, this.options.qrRefreshIntervalMs);
|
this._qrRefreshInterval = setInterval(getQrCode, this.options.qrRefreshIntervalMs);
|
||||||
|
|
||||||
// Wait for code scan
|
// Wait for code scan
|
||||||
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
|
try {
|
||||||
clearInterval(this._qrRefreshInterval);
|
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
|
||||||
this._qrRefreshInterval = undefined;
|
clearInterval(this._qrRefreshInterval);
|
||||||
|
this._qrRefreshInterval = undefined;
|
||||||
|
} catch(error) {
|
||||||
|
if (
|
||||||
|
error.name === 'ProtocolError' &&
|
||||||
|
error.message &&
|
||||||
|
error.message.match(/Target closed/)
|
||||||
|
) {
|
||||||
|
// something has called .destroy() while waiting
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.evaluate(ExposeStore, moduleRaid.toString());
|
await page.evaluate(ExposeStore, moduleRaid.toString());
|
||||||
@@ -430,11 +442,13 @@ class Client extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
this.emit(Events.READY);
|
this.emit(Events.READY);
|
||||||
|
|
||||||
// Disconnect when navigating away
|
// Disconnect when navigating away when in PAIRING state (detect logout)
|
||||||
// Because WhatsApp Web now reloads when logging out from the device, this also covers that case
|
|
||||||
this.pupPage.on('framenavigated', async () => {
|
this.pupPage.on('framenavigated', async () => {
|
||||||
this.emit(Events.DISCONNECTED, 'NAVIGATION');
|
const appState = await this.getState();
|
||||||
await this.destroy();
|
if(appState === WAState.PAIRING) {
|
||||||
|
this.emit(Events.DISCONNECTED, 'NAVIGATION');
|
||||||
|
await this.destroy();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,7 +741,7 @@ class Client extends EventEmitter {
|
|||||||
return await this.pupPage.evaluate(async chatId => {
|
return await this.pupPage.evaluate(async chatId => {
|
||||||
let chat = await window.Store.Chat.get(chatId);
|
let chat = await window.Store.Chat.get(chatId);
|
||||||
await window.Store.Cmd.archiveChat(chat, true);
|
await window.Store.Cmd.archiveChat(chat, true);
|
||||||
return chat.archive;
|
return true;
|
||||||
}, chatId);
|
}, chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -739,7 +753,7 @@ class Client extends EventEmitter {
|
|||||||
return await this.pupPage.evaluate(async chatId => {
|
return await this.pupPage.evaluate(async chatId => {
|
||||||
let chat = await window.Store.Chat.get(chatId);
|
let chat = await window.Store.Chat.get(chatId);
|
||||||
await window.Store.Cmd.archiveChat(chat, false);
|
await window.Store.Cmd.archiveChat(chat, false);
|
||||||
return chat.archive;
|
return false;
|
||||||
}, chatId);
|
}, chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class Chat extends Base {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if the chat is muted or not
|
* Indicates if the chat is muted or not
|
||||||
* @type {number}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.isMuted = data.isMuted;
|
this.isMuted = data.isMuted;
|
||||||
|
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ class Message extends Base {
|
|||||||
await this.client.pupPage.evaluate((msgId, everyone) => {
|
await this.client.pupPage.evaluate((msgId, everyone) => {
|
||||||
let msg = window.Store.Msg.get(msgId);
|
let msg = window.Store.Msg.get(msgId);
|
||||||
|
|
||||||
if (everyone && msg.id.fromMe && msg.canRevoke()) {
|
if (everyone && msg.id.fromMe && msg._canRevoke()) {
|
||||||
return window.Store.Cmd.sendRevokeMsgs(msg.chat, [msg], true);
|
return window.Store.Cmd.sendRevokeMsgs(msg.chat, [msg], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|||||||
window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default);
|
window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default);
|
||||||
window.Store.AppState = window.mR.findModule('STREAM')[0].Socket;
|
window.Store.AppState = window.mR.findModule('STREAM')[0].Socket;
|
||||||
window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
|
window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
|
||||||
window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
|
|
||||||
window.Store.Wap = window.mR.findModule('queryLinkPreview')[0].default;
|
window.Store.Wap = window.mR.findModule('queryLinkPreview')[0].default;
|
||||||
window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
|
window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
|
||||||
window.Store.SendClear = window.mR.findModule('sendClear')[0];
|
window.Store.SendClear = window.mR.findModule('sendClear')[0];
|
||||||
@@ -31,7 +30,7 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|||||||
window.Store.BlockContact = window.mR.findModule('blockContact')[0];
|
window.Store.BlockContact = window.mR.findModule('blockContact')[0];
|
||||||
window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default;
|
window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default;
|
||||||
window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
|
window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
|
||||||
window.Store.Label = window.mR.findModule('LabelCollection')[0].default;
|
window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection;
|
||||||
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].GK;
|
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].GK;
|
||||||
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
|
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
|
||||||
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
|
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
|
||||||
|
|||||||
160
tests/client.js
160
tests/client.js
@@ -7,7 +7,7 @@ const Contact = require('../src/structures/Contact');
|
|||||||
const Message = require('../src/structures/Message');
|
const Message = require('../src/structures/Message');
|
||||||
const MessageMedia = require('../src/structures/MessageMedia');
|
const MessageMedia = require('../src/structures/MessageMedia');
|
||||||
const Location = require('../src/structures/Location');
|
const Location = require('../src/structures/Location');
|
||||||
const { MessageTypes } = require('../src/util/Constants');
|
const { MessageTypes, WAState } = require('../src/util/Constants');
|
||||||
|
|
||||||
const remoteId = helper.remoteId;
|
const remoteId = helper.remoteId;
|
||||||
|
|
||||||
@@ -145,6 +145,46 @@ describe('Client', function() {
|
|||||||
|
|
||||||
await client.destroy();
|
await client.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can take over if client was logged in somewhere else with takeoverOnConflict=true', async function() {
|
||||||
|
this.timeout(40000);
|
||||||
|
|
||||||
|
const readyCallback1 = sinon.spy();
|
||||||
|
const readyCallback2 = sinon.spy();
|
||||||
|
const disconnectedCallback1 = sinon.spy();
|
||||||
|
const disconnectedCallback2 = sinon.spy();
|
||||||
|
|
||||||
|
const client1 = helper.createClient({
|
||||||
|
withSession: true,
|
||||||
|
options: { takeoverOnConflict: true, takeoverTimeoutMs: 5000 }
|
||||||
|
});
|
||||||
|
const client2 = helper.createClient({withSession: true});
|
||||||
|
|
||||||
|
client1.on('ready', readyCallback1);
|
||||||
|
client2.on('ready', readyCallback2);
|
||||||
|
client1.on('disconnected', disconnectedCallback1);
|
||||||
|
client2.on('disconnected', disconnectedCallback2);
|
||||||
|
|
||||||
|
await client1.initialize();
|
||||||
|
expect(readyCallback1.called).to.equal(true);
|
||||||
|
expect(readyCallback2.called).to.equal(false);
|
||||||
|
expect(disconnectedCallback1.called).to.equal(false);
|
||||||
|
expect(disconnectedCallback2.called).to.equal(false);
|
||||||
|
|
||||||
|
await client2.initialize();
|
||||||
|
expect(readyCallback2.called).to.equal(true);
|
||||||
|
expect(disconnectedCallback1.called).to.equal(false);
|
||||||
|
expect(disconnectedCallback2.called).to.equal(false);
|
||||||
|
|
||||||
|
// wait for takeoverTimeoutMs to kick in
|
||||||
|
await helper.sleep(5200);
|
||||||
|
expect(disconnectedCallback1.called).to.equal(false);
|
||||||
|
expect(disconnectedCallback2.called).to.equal(true);
|
||||||
|
expect(disconnectedCallback2.calledWith(WAState.CONFLICT)).to.equal(true);
|
||||||
|
|
||||||
|
await client1.destroy();
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Authenticated', function() {
|
describe('Authenticated', function() {
|
||||||
@@ -160,6 +200,12 @@ describe('Client', function() {
|
|||||||
await client.destroy();
|
await client.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can get current WhatsApp Web version', async function () {
|
||||||
|
const version = await client.getWWebVersion();
|
||||||
|
expect(typeof version).to.equal('string');
|
||||||
|
console.log(`WA Version: ${version}`);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Expose Store', function() {
|
describe('Expose Store', function() {
|
||||||
it('exposes the store', async function() {
|
it('exposes the store', async function() {
|
||||||
const exposed = await client.pupPage.evaluate(() => {
|
const exposed = await client.pupPage.evaluate(() => {
|
||||||
@@ -171,46 +217,46 @@ describe('Client', function() {
|
|||||||
|
|
||||||
it('exposes all required WhatsApp Web internal models', async function() {
|
it('exposes all required WhatsApp Web internal models', async function() {
|
||||||
const expectedModules = [
|
const expectedModules = [
|
||||||
'Chat',
|
|
||||||
'Msg',
|
|
||||||
'Contact',
|
|
||||||
'Conn',
|
|
||||||
'AppState',
|
'AppState',
|
||||||
'CryptoLib',
|
|
||||||
'Wap',
|
|
||||||
'SendSeen',
|
|
||||||
'SendClear',
|
|
||||||
'SendDelete',
|
|
||||||
'genId',
|
|
||||||
'SendMessage',
|
|
||||||
'MsgKey',
|
|
||||||
'Invite',
|
|
||||||
'OpaqueData',
|
|
||||||
'MediaPrep',
|
|
||||||
'MediaObject',
|
|
||||||
'MediaUpload',
|
|
||||||
'Cmd',
|
|
||||||
'MediaTypes',
|
|
||||||
'VCard',
|
|
||||||
'UserConstructor',
|
|
||||||
'Validators',
|
|
||||||
'WidFactory',
|
|
||||||
'BlockContact',
|
'BlockContact',
|
||||||
'GroupMetadata',
|
'Call',
|
||||||
'Sticker',
|
'Chat',
|
||||||
'UploadUtils',
|
'Cmd',
|
||||||
'Label',
|
'Conn',
|
||||||
|
'Contact',
|
||||||
|
'DownloadManager',
|
||||||
'Features',
|
'Features',
|
||||||
|
'GroupMetadata',
|
||||||
|
'Invite',
|
||||||
|
'Label',
|
||||||
|
'MediaObject',
|
||||||
|
'MediaPrep',
|
||||||
|
'MediaTypes',
|
||||||
|
'MediaUpload',
|
||||||
|
'Msg',
|
||||||
|
'MsgKey',
|
||||||
|
'OpaqueData',
|
||||||
'QueryOrder',
|
'QueryOrder',
|
||||||
'QueryProduct',
|
'QueryProduct',
|
||||||
'DownloadManager'
|
'SendClear',
|
||||||
|
'SendDelete',
|
||||||
|
'SendMessage',
|
||||||
|
'SendSeen',
|
||||||
|
'Sticker',
|
||||||
|
'UploadUtils',
|
||||||
|
'UserConstructor',
|
||||||
|
'VCard',
|
||||||
|
'Validators',
|
||||||
|
'Wap',
|
||||||
|
'WidFactory',
|
||||||
|
'genId'
|
||||||
];
|
];
|
||||||
|
|
||||||
const loadedModules = await client.pupPage.evaluate(() => {
|
const loadedModules = await client.pupPage.evaluate((expectedModules) => {
|
||||||
return Object.keys(window.Store);
|
return expectedModules.filter(m => Boolean(window.Store[m]));
|
||||||
});
|
}, expectedModules);
|
||||||
|
|
||||||
expect(loadedModules).to.include.members(expectedModules);
|
expect(loadedModules).to.have.members(expectedModules);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -486,5 +532,53 @@ END:VCARD`;
|
|||||||
expect(formatted).to.eql('+1 (809) 220-1111');
|
expect(formatted).to.eql('+1 (809) 220-1111');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Search messages', function () {
|
||||||
|
it('can search for messages', async function () {
|
||||||
|
this.timeout(5000);
|
||||||
|
|
||||||
|
const m1 = await client.sendMessage(remoteId, 'I\'m searching for Super Mario Brothers');
|
||||||
|
const m2 = await client.sendMessage(remoteId, 'This also contains Mario');
|
||||||
|
const m3 = await client.sendMessage(remoteId, 'Nothing of interest here, just Luigi');
|
||||||
|
|
||||||
|
// wait for search index to catch up
|
||||||
|
await helper.sleep(1000);
|
||||||
|
|
||||||
|
const msgs = await client.searchMessages('Mario', {chatId: remoteId});
|
||||||
|
expect(msgs.length).to.be.greaterThanOrEqual(2);
|
||||||
|
const msgIds = msgs.map(m => m.id._serialized);
|
||||||
|
expect(msgIds).to.include.members([
|
||||||
|
m1.id._serialized, m2.id._serialized
|
||||||
|
]);
|
||||||
|
expect(msgIds).to.not.include.members([m3.id._serialized]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Status/About', function () {
|
||||||
|
let me, previousStatus;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
me = await client.getContactById(client.info.wid._serialized);
|
||||||
|
previousStatus = await me.getAbout();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await client.setStatus(previousStatus);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can set the status text', async function () {
|
||||||
|
await client.setStatus('My shiny new status');
|
||||||
|
|
||||||
|
const status = await me.getAbout();
|
||||||
|
expect(status).to.eql('My shiny new status');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can set the status text to something else', async function () {
|
||||||
|
await client.setStatus('Busy');
|
||||||
|
|
||||||
|
const status = await me.getAbout();
|
||||||
|
expect(status).to.eql('Busy');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
188
tests/structures/chat.js
Normal file
188
tests/structures/chat.js
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
const { expect } = require('chai');
|
||||||
|
|
||||||
|
const helper = require('../helper');
|
||||||
|
const Message = require('../../src/structures/Message');
|
||||||
|
const { MessageTypes } = require('../../src/util/Constants');
|
||||||
|
const { Contact } = require('../../src/structures');
|
||||||
|
|
||||||
|
const remoteId = helper.remoteId;
|
||||||
|
|
||||||
|
describe('Chat', function () {
|
||||||
|
let client;
|
||||||
|
let chat;
|
||||||
|
|
||||||
|
before(async function() {
|
||||||
|
this.timeout(35000);
|
||||||
|
client = helper.createClient({ withSession: true });
|
||||||
|
await client.initialize();
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await client.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can send a message to a chat', async function () {
|
||||||
|
const msg = await chat.sendMessage('hello world');
|
||||||
|
expect(msg).to.be.instanceOf(Message);
|
||||||
|
expect(msg.type).to.equal(MessageTypes.TEXT);
|
||||||
|
expect(msg.fromMe).to.equal(true);
|
||||||
|
expect(msg.body).to.equal('hello world');
|
||||||
|
expect(msg.to).to.equal(remoteId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can fetch messages sent in a chat', async function () {
|
||||||
|
this.timeout(5000);
|
||||||
|
await helper.sleep(1000);
|
||||||
|
const msg = await chat.sendMessage('another message');
|
||||||
|
|
||||||
|
const messages = await chat.fetchMessages();
|
||||||
|
expect(messages.length).to.be.greaterThanOrEqual(2);
|
||||||
|
|
||||||
|
const fetchedMsg = messages[messages.length-1];
|
||||||
|
expect(fetchedMsg).to.be.instanceOf(Message);
|
||||||
|
expect(fetchedMsg.type).to.equal(MessageTypes.TEXT);
|
||||||
|
expect(fetchedMsg.id._serialized).to.equal(msg.id._serialized);
|
||||||
|
expect(fetchedMsg.body).to.equal(msg.body);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can use a limit when fetching messages sent in a chat', async function () {
|
||||||
|
await helper.sleep(1000);
|
||||||
|
const msg = await chat.sendMessage('yet another message');
|
||||||
|
|
||||||
|
const messages = await chat.fetchMessages({limit: 1});
|
||||||
|
expect(messages).to.have.lengthOf(1);
|
||||||
|
|
||||||
|
const fetchedMsg = messages[0];
|
||||||
|
expect(fetchedMsg).to.be.instanceOf(Message);
|
||||||
|
expect(fetchedMsg.type).to.equal(MessageTypes.TEXT);
|
||||||
|
expect(fetchedMsg.id._serialized).to.equal(msg.id._serialized);
|
||||||
|
expect(fetchedMsg.body).to.equal(msg.body);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can get the related contact', async function () {
|
||||||
|
const contact = await chat.getContact();
|
||||||
|
expect(contact).to.be.instanceOf(Contact);
|
||||||
|
expect(contact.id._serialized).to.equal(chat.id._serialized);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Seen', function () {
|
||||||
|
it('can mark a chat as unread', async function () {
|
||||||
|
await chat.markUnread();
|
||||||
|
await helper.sleep(500);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.unreadCount).to.equal(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can mark a chat as seen', async function () {
|
||||||
|
const res = await chat.sendSeen();
|
||||||
|
expect(res).to.equal(true);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.unreadCount).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Archiving', function (){
|
||||||
|
it('can archive a chat', async function () {
|
||||||
|
const res = await chat.archive();
|
||||||
|
expect(res).to.equal(true);
|
||||||
|
|
||||||
|
await helper.sleep(1000);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.archived).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can unarchive a chat', async function () {
|
||||||
|
const res = await chat.unarchive();
|
||||||
|
expect(res).to.equal(false);
|
||||||
|
|
||||||
|
await helper.sleep(1000);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.archived).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Pinning', function () {
|
||||||
|
it('can pin a chat', async function () {
|
||||||
|
const res = await chat.pin();
|
||||||
|
expect(res).to.equal(true);
|
||||||
|
|
||||||
|
await helper.sleep(1000);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.pinned).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can unpin a chat', async function () {
|
||||||
|
const res = await chat.unpin();
|
||||||
|
expect(res).to.equal(false);
|
||||||
|
await helper.sleep(1000);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.pinned).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Muting', function () {
|
||||||
|
it('can mute a chat forever', async function() {
|
||||||
|
await chat.mute();
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.isMuted).to.equal(true);
|
||||||
|
expect(chat.muteExpiration).to.equal(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can mute a chat until a specific date', async function() {
|
||||||
|
const unmuteDate = new Date(new Date().getTime() + (1000*60*60));
|
||||||
|
await chat.mute(unmuteDate);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.isMuted).to.equal(true);
|
||||||
|
expect(chat.muteExpiration).to.equal(
|
||||||
|
Math.round(unmuteDate.getTime() / 1000)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can unmute a chat', async function () {
|
||||||
|
await chat.unmute();
|
||||||
|
await helper.sleep(500);
|
||||||
|
|
||||||
|
// refresh chat
|
||||||
|
chat = await client.getChatById(remoteId);
|
||||||
|
expect(chat.isMuted).to.equal(false);
|
||||||
|
expect(chat.muteExpiration).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line mocha/no-skipped-tests
|
||||||
|
describe.skip('Destructive operations', function () {
|
||||||
|
it('can clear all messages from chat', async function () {
|
||||||
|
this.timeout(5000);
|
||||||
|
|
||||||
|
const res = await chat.clearMessages();
|
||||||
|
expect(res).to.equal(true);
|
||||||
|
|
||||||
|
await helper.sleep(3000);
|
||||||
|
|
||||||
|
const msgs = await chat.fetchMessages();
|
||||||
|
expect(msgs).to.have.lengthOf(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can delete a chat', async function () {
|
||||||
|
const res = await chat.delete();
|
||||||
|
expect(res).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1 +1 @@
|
|||||||
2.2202.8
|
2.2202.12
|
||||||
Reference in New Issue
Block a user