From b4910442d63b5e071eb0d1e4b67a4f572755a773 Mon Sep 17 00:00:00 2001 From: kai Date: Wed, 24 Mar 2021 14:11:30 -0700 Subject: [PATCH 1/2] Initial Commit --- .../messaging/test/test-receive-background.js | 157 ++++++++++++++++++ ...est-send.js => test-receive-foreground.js} | 144 +--------------- ...st-deleteToken.js => test-token-delete.js} | 4 +- ...st-updateToken.js => test-token-update.js} | 2 +- .../test/test-useDefaultServiceWorker.js | 2 - .../messaging/test/test-useValidManifest.js | 2 - .../test/utils/checkMessageReceived.js | 66 ++++++++ .../messaging/test/utils/checkSendResponse.js | 22 +++ 8 files changed, 256 insertions(+), 143 deletions(-) create mode 100644 integration/messaging/test/test-receive-background.js rename integration/messaging/test/{test-send.js => test-receive-foreground.js} (52%) rename integration/messaging/test/{test-deleteToken.js => test-token-delete.js} (97%) rename integration/messaging/test/{test-updateToken.js => test-token-update.js} (99%) create mode 100644 integration/messaging/test/utils/checkMessageReceived.js create mode 100644 integration/messaging/test/utils/checkSendResponse.js diff --git a/integration/messaging/test/test-receive-background.js b/integration/messaging/test/test-receive-background.js new file mode 100644 index 00000000000..258bff32051 --- /dev/null +++ b/integration/messaging/test/test-receive-background.js @@ -0,0 +1,157 @@ +/** + * @license + * Copyright 2017 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const testServer = require('./utils/test-server'); +const sendMessage = require('./utils/sendMessage'); +const retrieveToken = require('./utils/retrieveToken'); +const seleniumAssistant = require('selenium-assistant'); +const getReceivedBackgroundMessages = require('./utils/getReceivedBackgroundMessages'); +const createPermittedWebDriver = require('./utils/createPermittedWebDriver'); +const checkSendResponse = require('./utils/checkSendResponse'); +const checkMessageReceived = require('./utils/checkMessageReceived'); +const openNewTab = require('./utils/openNewTab'); + +const TEST_DOMAINS = ['valid-vapid-key-modern-sw']; + +// 4 minutes. The fact that the flow includes making a request to the Send Service, +// storing/retrieving form indexedDb asynchronously makes these test units to have a execution time +// variance. Therefore, allowing these units to have a longer time to work is crucial. +const TIMEOUT_BACKGROUND_MESSAGE_TEST_UNIT_MILLISECONDS = 240000; + +// 1 minute. Wait for object store to be created and received message to be stored in idb. This +// waiting time MUST be longer than the wait time for adding to db in the sw. +const WAIT_TIME_BEFORE_RETRIEVING_BACKGROUND_MESSAGES_MILLISECONDS = 60000; + +const wait = ms => new Promise(res => setTimeout(res, ms)); + +// 50% of integration test run time is spent in testing receiving in background. Running these +// slower tests last so other tests can fail quickly if they do fail. +require('./test-token-delete'); +require('./test-token-update'); +require('./test-useValidManifest'); +require('./test-useDefaultServiceWorker'); +require('./test-receive-foreground'); + +describe('Firebase Messaging Integration Tests > Test Background Receive', function () { + this.retries(2); + let globalWebDriver; + + before(async function () { + await testServer.start(); + }); + + after(async function () { + await testServer.stop(); + }); + + // TODO: enable testing for firefox + seleniumAssistant.getLocalBrowsers().forEach(assistantBrowser => { + if (assistantBrowser.getId() !== 'chrome') { + return; + } + + TEST_DOMAINS.forEach(domain => { + describe(`Testing browser: ${assistantBrowser.getPrettyName()} : ${domain}`, function () { + before(async function () { + globalWebDriver = createPermittedWebDriver( + /* browser= */ assistantBrowser.getId() + ); + }); + + it('Background app can receive a {} empty message from sw', async function () { + this.timeout(TIMEOUT_BACKGROUND_MESSAGE_TEST_UNIT_MILLISECONDS); + + // Clearing the cache and db data by killing the previously instantiated driver. Note that + // ideally this call is placed inside the after/before hooks. However, Mocha forbids + // operations longer than 2s in hooks. Hence, this clearing call needs to be inside the + // test unit. + await seleniumAssistant.killWebDriver(globalWebDriver); + + globalWebDriver = createPermittedWebDriver( + /* browser= */ assistantBrowser.getId() + ); + + prepareBackgroundApp(globalWebDriver, domain); + + checkSendResponse( + await sendMessage({ + to: await retrieveToken(globalWebDriver) + }) + ); + + await wait( + WAIT_TIME_BEFORE_RETRIEVING_BACKGROUND_MESSAGES_MILLISECONDS + ); + + checkMessageReceived( + await getReceivedBackgroundMessages(globalWebDriver), + /* expectedNotificationPayload= */ null, + /* expectedDataPayload= */ null, + /* isLegacyPayload= */ false + ); + }); + + it('Background app can receive a {"data"} message frow sw', async function () { + this.timeout(TIMEOUT_BACKGROUND_MESSAGE_TEST_UNIT_MILLISECONDS); + + await seleniumAssistant.killWebDriver(globalWebDriver); + + globalWebDriver = createPermittedWebDriver( + /* browser= */ assistantBrowser.getId() + ); + + prepareBackgroundApp(globalWebDriver, domain); + + checkSendResponse( + await sendMessage({ + to: await retrieveToken(globalWebDriver), + data: getTestDataPayload() + }) + ); + + await wait( + WAIT_TIME_BEFORE_RETRIEVING_BACKGROUND_MESSAGES_MILLISECONDS + ); + + checkMessageReceived( + await getReceivedBackgroundMessages(globalWebDriver), + /* expectedNotificationPayload= */ null, + /* expectedDataPayload= */ getTestDataPayload() + ); + }); + }); + }); + }); +}); + +async function prepareBackgroundApp(globalWebDriver, domain) { + await globalWebDriver.get(`${testServer.serverAddress}/${domain}/`); + // TODO: remove the try/catch block once the underlying bug has been resolved. Shift window focus + // away from app window so that background messages can be received/processed + try { + await openNewTab(globalWebDriver); + } catch (err) { + // ChromeDriver seems to have an open bug which throws "JavascriptError: javascript error: + // circular reference". Nevertheless, a new tab can still be opened. Hence, just catch and + // continue here. + console.log('FCM (ignored on purpose): ' + err); + } +} + +function getTestDataPayload() { + return { hello: 'world' }; +} diff --git a/integration/messaging/test/test-send.js b/integration/messaging/test/test-receive-foreground.js similarity index 52% rename from integration/messaging/test/test-send.js rename to integration/messaging/test/test-receive-foreground.js index 93ead480819..b6283fd7c71 100644 --- a/integration/messaging/test/test-send.js +++ b/integration/messaging/test/test-receive-foreground.js @@ -15,41 +15,21 @@ * limitations under the License. */ -const expect = require('chai').expect; const testServer = require('./utils/test-server'); const sendMessage = require('./utils/sendMessage'); const retrieveToken = require('./utils/retrieveToken'); const seleniumAssistant = require('selenium-assistant'); -const getReceivedBackgroundMessages = require('./utils/getReceivedBackgroundMessages'); +const checkSendResponse = require('./utils/checkSendResponse'); const getReceivedForegroundMessages = require('./utils/getReceivedForegroundMessages'); -const openNewTab = require('./utils/openNewTab'); +const checkMessageReceived = require('./utils/checkMessageReceived'); const createPermittedWebDriver = require('./utils/createPermittedWebDriver'); -const TEST_DOMAINS = ['valid-vapid-key', 'valid-vapid-key-modern-sw']; -const TEST_PROJECT_SENDER_ID = '750970317741'; -const DEFAULT_COLLAPSE_KEY_VALUE = 'do_not_collapse'; -const FIELD_FROM = 'from'; -const FIELD_COLLAPSE_KEY_LEGACY = 'collapse_key'; -const FIELD_COLLAPSE_KEY = 'collapseKey'; - -const FIELD_DATA = 'data'; -const FIELD_NOTIFICATION = 'notification'; - -// 4 minutes. The fact that the flow includes making a request to the Send Service, -// storing/retrieving form indexedDb asynchronously makes these test units to have a execution time -// variance. Therefore, allowing these units to have a longer time to work is crucial. -const TIMEOUT_BACKGROUND_MESSAGE_TEST_UNIT_MILLISECONDS = 240000; - +// Only testing 'valid-vapid-key' because 'valid-vapid-key-modern-sw' has the same behavior +const TEST_DOMAINS = ['valid-vapid-key']; const TIMEOUT_FOREGROUND_MESSAGE_TEST_UNIT_MILLISECONDS = 120000; -// 1 minute. Wait for object store to be created and received message to be stored in idb. This -// waiting time MUST be longer than the wait time for adding to db in the sw. -const WAIT_TIME_BEFORE_RETRIEVING_BACKGROUND_MESSAGES_MILLISECONDS = 60000; - -const wait = ms => new Promise(res => setTimeout(res, ms)); - -describe('Starting Integration Test > Sending and Receiving ', function () { - this.retries(3); +describe('Firebase Messaging Integration Tests > Test Foreground Receive', function () { + this.retries(2); let globalWebDriver; before(async function () { @@ -73,68 +53,6 @@ describe('Starting Integration Test > Sending and Receiving ', function () { /* browser= */ assistantBrowser.getId() ); }); - - it('Background app can receive a {} empty message from sw', async function () { - this.timeout(TIMEOUT_BACKGROUND_MESSAGE_TEST_UNIT_MILLISECONDS); - - // Clearing the cache and db data by killing the previously instantiated driver. Note that - // ideally this call is placed inside the after/before hooks. However, Mocha forbids - // operations longer than 2s in hooks. Hence, this clearing call needs to be inside the - // test unit. - await seleniumAssistant.killWebDriver(globalWebDriver); - - globalWebDriver = createPermittedWebDriver( - /* browser= */ assistantBrowser.getId() - ); - - prepareBackgroundApp(globalWebDriver, domain); - - checkSendResponse( - await sendMessage({ - to: await retrieveToken(globalWebDriver) - }) - ); - - await wait( - WAIT_TIME_BEFORE_RETRIEVING_BACKGROUND_MESSAGES_MILLISECONDS - ); - - checkMessageReceived( - await getReceivedBackgroundMessages(globalWebDriver), - /* expectedNotificationPayload= */ null, - /* expectedDataPayload= */ null, - /* isLegacyPayload= */ false - ); - }); - - it('Background app can receive a {"data"} message frow sw', async function () { - this.timeout(TIMEOUT_BACKGROUND_MESSAGE_TEST_UNIT_MILLISECONDS); - - await seleniumAssistant.killWebDriver(globalWebDriver); - - globalWebDriver = createPermittedWebDriver( - /* browser= */ assistantBrowser.getId() - ); - - prepareBackgroundApp(globalWebDriver, domain); - - checkSendResponse( - await sendMessage({ - to: await retrieveToken(globalWebDriver), - data: getTestDataPayload() - }) - ); - - await wait( - WAIT_TIME_BEFORE_RETRIEVING_BACKGROUND_MESSAGES_MILLISECONDS - ); - - checkMessageReceived( - await getReceivedBackgroundMessages(globalWebDriver), - /* expectedNotificationPayload= */ null, - /* expectedDataPayload= */ getTestDataPayload() - ); - }); }); it('Foreground app can receive a {} empty message in onMessage', async function () { @@ -241,35 +159,8 @@ describe('Starting Integration Test > Sending and Receiving ', function () { }); }); -function checkMessageReceived( - receivedMessages, - expectedNotificationPayload, - expectedDataPayload -) { - expect(receivedMessages).to.exist; - - const message = receivedMessages[0]; - - expect(message[FIELD_FROM]).to.equal(TEST_PROJECT_SENDER_ID); - const collapseKey = !!message[FIELD_COLLAPSE_KEY_LEGACY] - ? message[FIELD_COLLAPSE_KEY_LEGACY] - : message[FIELD_COLLAPSE_KEY]; - expect(collapseKey).to.equal(DEFAULT_COLLAPSE_KEY_VALUE); - - if (expectedNotificationPayload) { - expect(message[FIELD_NOTIFICATION]).to.deep.equal( - getTestNotificationPayload() - ); - } - - if (expectedDataPayload) { - expect(message[FIELD_DATA]).to.deep.equal(getTestDataPayload()); - } -} - -function checkSendResponse(response) { - expect(response).to.exist; - expect(response.success).to.equal(1); +function getTestDataPayload() { + return { hello: 'world' }; } function getTestNotificationPayload() { @@ -281,22 +172,3 @@ function getTestNotificationPayload() { tag: 'test-tag' }; } - -function getTestDataPayload() { - return { hello: 'world' }; -} - -async function prepareBackgroundApp(globalWebDriver, domain) { - await globalWebDriver.get(`${testServer.serverAddress}/${domain}/`); - - // TODO: remove the try/catch block once the underlying bug has been resolved. Shift window focus - // away from app window so that background messages can be received/processed - try { - await openNewTab(globalWebDriver); - } catch (err) { - // ChromeDriver seems to have an open bug which throws "JavascriptError: javascript error: - // circular reference". Nevertheless, a new tab can still be opened. Hence, just catch and - // continue here. - console.log('FCM (ignored on purpose): ' + err); - } -} diff --git a/integration/messaging/test/test-deleteToken.js b/integration/messaging/test/test-token-delete.js similarity index 97% rename from integration/messaging/test/test-deleteToken.js rename to integration/messaging/test/test-token-delete.js index cb6aa341088..d3f0fca908e 100644 --- a/integration/messaging/test/test-deleteToken.js +++ b/integration/messaging/test/test-token-delete.js @@ -23,12 +23,12 @@ const retrieveToken = require('./utils/retrieveToken'); const seleniumAssistant = require('selenium-assistant'); const createPermittedWebDriver = require('./utils/createPermittedWebDriver'); -const TEST_SUITE_TIMEOUT_MS = 100000; +const TEST_SUITE_TIMEOUT_MS = 20000; const TEST_DOMAIN = 'valid-vapid-key'; describe('Firebase Messaging Integration Tests > get and delete token', function () { this.timeout(TEST_SUITE_TIMEOUT_MS); - this.retries(3); + this.retries(2); let globalWebDriver; before(async function () { diff --git a/integration/messaging/test/test-updateToken.js b/integration/messaging/test/test-token-update.js similarity index 99% rename from integration/messaging/test/test-updateToken.js rename to integration/messaging/test/test-token-update.js index 2de606be2a9..ce2832e38ee 100644 --- a/integration/messaging/test/test-updateToken.js +++ b/integration/messaging/test/test-token-update.js @@ -30,7 +30,7 @@ const TEST_DOMAIN = 'valid-vapid-key'; describe('Firebase Messaging Integration Tests > update a token', function () { this.timeout(TEST_SUITE_TIMEOUT_MS); - this.retries(3); + this.retries(2); let globalWebDriver; diff --git a/integration/messaging/test/test-useDefaultServiceWorker.js b/integration/messaging/test/test-useDefaultServiceWorker.js index 0d29f22b0ab..3012e73161b 100644 --- a/integration/messaging/test/test-useDefaultServiceWorker.js +++ b/integration/messaging/test/test-useDefaultServiceWorker.js @@ -27,8 +27,6 @@ const TEST_SUITE_TIMEOUT_MS = 70000; describe(`Firebase Messaging Integration Tests > Use 'firebase-messaging-sw.js' by default`, function () { this.timeout(TEST_SUITE_TIMEOUT_MS); - this.retries(3); - let globalWebDriver; before(async function () { diff --git a/integration/messaging/test/test-useValidManifest.js b/integration/messaging/test/test-useValidManifest.js index da2a8c3f15f..d3319927c01 100644 --- a/integration/messaging/test/test-useValidManifest.js +++ b/integration/messaging/test/test-useValidManifest.js @@ -27,8 +27,6 @@ const TEST_SUITE_TIMEOUT_MS = 70000; describe(`Firebase Messaging Integration Tests > Use 'use valid manifest`, function () { this.timeout(TEST_SUITE_TIMEOUT_MS); - this.retries(3); - let globalWebDriver; before(async function () { diff --git a/integration/messaging/test/utils/checkMessageReceived.js b/integration/messaging/test/utils/checkMessageReceived.js new file mode 100644 index 00000000000..c407ae6b9b8 --- /dev/null +++ b/integration/messaging/test/utils/checkMessageReceived.js @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const expect = require('chai').expect; + +const TEST_PROJECT_SENDER_ID = '750970317741'; +const DEFAULT_COLLAPSE_KEY_VALUE = 'do_not_collapse'; +const FIELD_FROM = 'from'; +const FIELD_COLLAPSE_KEY_LEGACY = 'collapse_key'; +const FIELD_COLLAPSE_KEY = 'collapseKey'; + +const FIELD_DATA = 'data'; +const FIELD_NOTIFICATION = 'notification'; + +module.exports = ( + receivedMessages, + expectedNotificationPayload, + expectedDataPayload +) => { + expect(receivedMessages).to.exist; + + const message = receivedMessages[0]; + + expect(message[FIELD_FROM]).to.equal(TEST_PROJECT_SENDER_ID); + const collapseKey = !!message[FIELD_COLLAPSE_KEY_LEGACY] + ? message[FIELD_COLLAPSE_KEY_LEGACY] + : message[FIELD_COLLAPSE_KEY]; + expect(collapseKey).to.equal(DEFAULT_COLLAPSE_KEY_VALUE); + + if (expectedNotificationPayload) { + expect(message[FIELD_NOTIFICATION]).to.deep.equal( + getTestNotificationPayload() + ); + } + + if (expectedDataPayload) { + expect(message[FIELD_DATA]).to.deep.equal(getTestDataPayload()); + } +}; + +function getTestNotificationPayload() { + return { + title: 'test title', + body: 'test body', + icon: '/test/icon.png', + click_action: '/', + tag: 'test-tag' + }; +} + +function getTestDataPayload() { + return { hello: 'world' }; +} diff --git a/integration/messaging/test/utils/checkSendResponse.js b/integration/messaging/test/utils/checkSendResponse.js new file mode 100644 index 00000000000..5c43f78ef8a --- /dev/null +++ b/integration/messaging/test/utils/checkSendResponse.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const expect = require('chai').expect; + +module.exports = response => { + expect(response).to.exist; + expect(response.success).to.equal(1); +}; From c1877d53ff61e17a5f0f46c42a489ea1b60d6a31 Mon Sep 17 00:00:00 2001 From: kai Date: Wed, 24 Mar 2021 14:21:20 -0700 Subject: [PATCH 2/2] Let get_delete_token run first --- integration/messaging/test/test-receive-foreground.js | 3 +++ integration/messaging/test/test-token-update.js | 3 +++ integration/messaging/test/test-useDefaultServiceWorker.js | 3 +++ integration/messaging/test/test-useValidManifest.js | 3 +++ 4 files changed, 12 insertions(+) diff --git a/integration/messaging/test/test-receive-foreground.js b/integration/messaging/test/test-receive-foreground.js index b6283fd7c71..8c23a07fae6 100644 --- a/integration/messaging/test/test-receive-foreground.js +++ b/integration/messaging/test/test-receive-foreground.js @@ -28,6 +28,9 @@ const createPermittedWebDriver = require('./utils/createPermittedWebDriver'); const TEST_DOMAINS = ['valid-vapid-key']; const TIMEOUT_FOREGROUND_MESSAGE_TEST_UNIT_MILLISECONDS = 120000; +// Getting and deleting token is the entry step of using FM SDK. Let it run first and fail quickly. +require('./test-token-delete'); + describe('Firebase Messaging Integration Tests > Test Foreground Receive', function () { this.retries(2); let globalWebDriver; diff --git a/integration/messaging/test/test-token-update.js b/integration/messaging/test/test-token-update.js index ce2832e38ee..d2fc33782c1 100644 --- a/integration/messaging/test/test-token-update.js +++ b/integration/messaging/test/test-token-update.js @@ -28,6 +28,9 @@ const getErrors = require('./utils/getErrors'); const TEST_SUITE_TIMEOUT_MS = 70000; const TEST_DOMAIN = 'valid-vapid-key'; +// Getting and deleting token is the entry step of using FM SDK. Let it run first and fail quickly. +require('./test-token-delete'); + describe('Firebase Messaging Integration Tests > update a token', function () { this.timeout(TEST_SUITE_TIMEOUT_MS); this.retries(2); diff --git a/integration/messaging/test/test-useDefaultServiceWorker.js b/integration/messaging/test/test-useDefaultServiceWorker.js index 3012e73161b..0e3a903042f 100644 --- a/integration/messaging/test/test-useDefaultServiceWorker.js +++ b/integration/messaging/test/test-useDefaultServiceWorker.js @@ -24,6 +24,9 @@ const createPermittedWebDriver = require('./utils/createPermittedWebDriver'); const TEST_DOMAIN = 'default-sw'; const TEST_SUITE_TIMEOUT_MS = 70000; +// Getting and deleting token is the entry step of using FM SDK. Let it run first and fail quickly. +require('./test-token-delete'); + describe(`Firebase Messaging Integration Tests > Use 'firebase-messaging-sw.js' by default`, function () { this.timeout(TEST_SUITE_TIMEOUT_MS); diff --git a/integration/messaging/test/test-useValidManifest.js b/integration/messaging/test/test-useValidManifest.js index d3319927c01..4c566fc9eb4 100644 --- a/integration/messaging/test/test-useValidManifest.js +++ b/integration/messaging/test/test-useValidManifest.js @@ -24,6 +24,9 @@ const createPermittedWebDriver = require('./utils/createPermittedWebDriver'); const TEST_DOMAIN = 'valid-manifest'; const TEST_SUITE_TIMEOUT_MS = 70000; +// Getting and deleting token is the entry step of using FM SDK. Let it run first and fail quickly. +require('./test-token-delete'); + describe(`Firebase Messaging Integration Tests > Use 'use valid manifest`, function () { this.timeout(TEST_SUITE_TIMEOUT_MS);