Fixed firefox Snaps + add initial end-to-end tests (#13671)

* Changed registryUrl for snaps only in firefox
Fixed getPlatform to only be imported into metamask-controller in flask
Removed snaps specific testrunner script and use run-all with a cli option

* Fixed flakey tests

* Removed unneeded await

* Added delay

* Fixed linting
feature/default_network_editable
Shane 3 years ago committed by GitHub
parent 0e41bd4399
commit 1f55af3151
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 87
      .circleci/config.yml
  2. 8
      app/scripts/metamask-controller.js
  3. 3
      package.json
  4. 20
      test/e2e/run-all.js
  5. 98
      test/e2e/snaps/test-snap-confirm.spec.js
  6. 90
      test/e2e/snaps/test-snap-error.spec.js
  7. 2
      test/e2e/webdriver/chrome.js
  8. 2
      test/e2e/webdriver/driver.js
  9. 13
      test/e2e/webdriver/firefox.js
  10. 4
      test/e2e/webdriver/index.js
  11. 2
      ui/pages/permissions-connect/permissions-connect.component.js

@ -53,6 +53,9 @@ workflows:
- prep-build-test:
requires:
- prep-deps
- prep-build-test-flask:
requires:
- prep-deps
- prep-build-test-metrics:
requires:
- prep-deps
@ -78,6 +81,12 @@ workflows:
- test-e2e-firefox:
requires:
- prep-build-test
- test-e2e-chrome-snaps:
requires:
- prep-build-test-flask
- test-e2e-firefox-snaps:
requires:
- prep-build-test-flask
- test-e2e-chrome-metrics:
requires:
- prep-build-test-metrics
@ -130,6 +139,8 @@ workflows:
- test-e2e-firefox
- test-e2e-chrome-metrics
- test-e2e-firefox-metrics
- test-e2e-chrome-snaps
- test-e2e-firefox-snaps
- benchmark:
requires:
- prep-build-test
@ -283,6 +294,28 @@ jobs:
- dist-flask
- builds-flask
prep-build-test-flask:
executor: node-browsers-medium-plus
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Build extension for testing
command: yarn build:test:flask
- run:
name: Move test build to 'dist-test' to avoid conflict with production build
command: mv ./dist ./dist-test-flask
- run:
name: Move test zips to 'builds-test' to avoid conflict with production build
command: mv ./builds ./builds-test-flask
- persist_to_workspace:
root: .
paths:
- dist-test-flask
- builds-test-flask
prep-build-test:
executor: node-browsers-medium-plus
steps:
@ -465,6 +498,60 @@ jobs:
path: test-artifacts
destination: test-artifacts
test-e2e-firefox-snaps:
executor: node-browsers
steps:
- checkout
- run:
name: Install Firefox
command: ./.circleci/scripts/firefox-install.sh
- attach_workspace:
at: .
- run:
name: Move test build to dist
command: mv ./dist-test-flask ./dist
- run:
name: Move test zips to builds
command: mv ./builds-test-flask ./builds
- run:
name: test:e2e:firefox:snaps
command: |
if .circleci/scripts/test-run-e2e.sh
then
yarn test:e2e:firefox:snaps --retries 2
fi
no_output_timeout: 20m
- store_artifacts:
path: test-artifacts
destination: test-artifacts
test-e2e-chrome-snaps:
executor: node-browsers
steps:
- checkout
- run:
name: Re-Install Chrome
command: ./.circleci/scripts/chrome-install.sh
- attach_workspace:
at: .
- run:
name: Move test build to dist
command: mv ./dist-test-flask ./dist
- run:
name: Move test zips to builds
command: mv ./builds-test-flask ./builds
- run:
name: test:e2e:chrome:snaps
command: |
if .circleci/scripts/test-run-e2e.sh
then
yarn test:e2e:chrome:snaps --retries 2
fi
no_output_timeout: 20m
- store_artifacts:
path: test-artifacts
destination: test-artifacts
test-e2e-chrome-metrics:
executor: node-browsers
steps:

@ -74,6 +74,7 @@ import { MILLISECOND } from '../../shared/constants/time';
import {
///: BEGIN:ONLY_INCLUDE_IN(flask)
MESSAGE_TYPE,
PLATFORM_FIREFOX,
///: END:ONLY_INCLUDE_IN
POLLING_TOKEN_ENVIRONMENT_TYPES,
SUBJECT_TYPES,
@ -134,6 +135,10 @@ import {
///: END:ONLY_INCLUDE_IN
} from './controllers/permissions';
///: BEGIN:ONLY_INCLUDE_IN(flask)
import { getPlatform } from './lib/util';
///: END:ONLY_INCLUDE_IN
export const METAMASK_CONTROLLER_EVENTS = {
// Fired after state changes that impact the extension badge (unapproved msg count)
// The process of updating the badge happens in app/scripts/background.js.
@ -607,7 +612,10 @@ export default class MetamaskController extends EventEmitter {
],
});
const usingFirefox = getPlatform() === PLATFORM_FIREFOX;
this.snapController = new SnapController({
npmRegistryUrl: usingFirefox ? 'https://registry.npmjs.cf/' : undefined,
endowmentPermissionNames: Object.values(EndowmentPermissions),
terminateAllSnaps: this.workerController.terminateAllSnaps.bind(
this.workerController,

@ -18,6 +18,7 @@
"benchmark:chrome": "SELENIUM_BROWSER=chrome node test/e2e/benchmark.js",
"benchmark:firefox": "SELENIUM_BROWSER=firefox node test/e2e/benchmark.js",
"build:test": "yarn build test",
"build:test:flask": "yarn build test --build-type flask",
"build:test:metrics": "SEGMENT_HOST='http://localhost:9090' SEGMENT_WRITE_KEY='FAKE' yarn build test",
"test": "yarn lint && yarn test:unit && yarn test:unit:jest",
"dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080",
@ -30,8 +31,10 @@
"test:unit:mocha": "mocha './app/**/*.test.js'",
"test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js",
"test:e2e:chrome:metrics": "SELENIUM_BROWSER=chrome node test/e2e/run-e2e-test.js test/e2e/metrics.spec.js",
"test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps",
"test:e2e:firefox": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js",
"test:e2e:firefox:metrics": "SELENIUM_BROWSER=firefox node test/e2e/run-e2e-test.js test/e2e/metrics.spec.js",
"test:e2e:firefox:snaps": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js --snaps",
"test:e2e:single": "node test/e2e/run-e2e-test.js",
"test:coverage:mocha": "nyc --reporter=text --reporter=html yarn test:unit:mocha",
"test:coverage:jest": "yarn test:unit:jest --coverage --maxWorkers=2",

@ -17,6 +17,10 @@ async function main() {
type: 'string',
choices: ['chrome', 'firefox'],
})
.option('snaps', {
description: `run snaps e2e tests`,
type: 'boolean',
})
.option('retries', {
description:
'Set how many times the test should be retried upon failure.',
@ -26,16 +30,22 @@ async function main() {
.strict()
.help('help');
const { browser, retries } = argv;
const { browser, retries, snaps } = argv;
let testDir = path.join(__dirname, 'tests');
const testDir = path.join(__dirname, 'tests');
const metamaskUiTest = path.join(__dirname, 'metamask-ui.spec.js');
if (snaps) {
testDir = path.join(__dirname, 'snaps');
}
const testFilenames = await fs.readdir(testDir);
const testPaths = testFilenames.map((filename) =>
path.join(testDir, filename),
);
const allE2eTestPaths = [...testPaths, metamaskUiTest];
if (!snaps) {
testPaths.push(path.join(__dirname, 'metamask-ui.spec.js'));
}
const runE2eTestPath = path.join(__dirname, 'run-e2e-test.js');
@ -47,7 +57,7 @@ async function main() {
args.push('--retries', retries);
}
for (const testPath of allE2eTestPaths) {
for (const testPath of testPaths) {
await runInShell('node', [...args, testPath]);
}
}

@ -0,0 +1,98 @@
const { strict: assert } = require('assert');
const { withFixtures } = require('../helpers');
describe('Test Snap Confirm', function () {
it('can pop up a snap confirm and get its result', async function () {
const ganacheOptions = {
accounts: [
{
secretKey:
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
balance: 25000000000000000000,
},
],
};
await withFixtures(
{
fixtures: 'imported-account',
ganacheOptions,
title: this.test.title,
driverOptions: {
type: 'flask',
},
},
async ({ driver }) => {
await driver.navigate();
// enter pw into extension
await driver.fill('#password', 'correct horse battery staple');
await driver.press('#password', driver.Key.ENTER);
// navigate to test snaps page and connect
await driver.driver.get('https://metamask.github.io/test-snaps/');
await driver.fill('.snapId', 'npm:@metamask/test-snap-confirm');
await driver.clickElement({
text: 'Connect To Confirm Snap',
tag: 'button',
});
// switch to metamask extension and click connect
await driver.waitUntilXWindowHandles(2, 5000, 10000);
let windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.clickElement(
{
text: 'Connect',
tag: 'button',
},
10000,
);
await driver.delay(2000);
// approve install of snap
await driver.waitUntilXWindowHandles(2, 5000, 10000);
windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.clickElement({
text: 'Approve & Install',
tag: 'button',
});
// click send inputs on test snap page
await driver.waitUntilXWindowHandles(1, 5000, 10000);
windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
await driver.clickElement({
text: 'Send Inputs to Hello Snap',
tag: 'button',
});
// hit 'approve' on the custom confirm
await driver.waitUntilXWindowHandles(2, 5000, 10000);
windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.clickElement({
text: 'Approve',
tag: 'button',
});
// check the results of the custom confirm
await driver.waitUntilXWindowHandles(1, 5000, 10000);
windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
const confirmResult = await driver.findElement('.sendResults');
assert.equal(await confirmResult.getText(), 'true');
},
);
});
});

@ -0,0 +1,90 @@
const { strict: assert } = require('assert');
const { withFixtures } = require('../helpers');
const { PAGES } = require('../webdriver/driver');
describe('Test Snap Error', function () {
it('can pop up a snap error and see the error', async function () {
const ganacheOptions = {
accounts: [
{
secretKey:
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
balance: 25000000000000000000,
},
],
};
await withFixtures(
{
fixtures: 'imported-account',
ganacheOptions,
title: this.test.title,
driverOptions: { type: 'flask' },
},
async ({ driver }) => {
await driver.navigate();
// enter pw into extension
await driver.fill('#password', 'correct horse battery staple');
await driver.press('#password', driver.Key.ENTER);
// navigate to test snaps page and connect
await driver.driver.get('https://metamask.github.io/test-snaps/');
await driver.fill('.snapId2', 'npm:@metamask/test-snap-error');
await driver.clickElement({
text: 'Connect Error Snap',
tag: 'button',
});
// switch to metamask extension and click connect
await driver.waitUntilXWindowHandles(2, 5000, 10000);
let windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.clickElement(
{
text: 'Connect',
tag: 'button',
},
10000,
);
await driver.delay(2000);
// approve install of snap
windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.clickElement({
text: 'Approve & Install',
tag: 'button',
});
// click send inputs on test snap page
await driver.waitUntilXWindowHandles(1, 5000, 10000);
windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
await driver.clickElement({
text: 'Send Test to Error Snap',
tag: 'button',
});
await driver.navigate(PAGES.HOME);
const error = await driver.findElement(
'.home-notification__content-container',
);
const text = await error.getText();
assert.equal(
text.includes(
"Snap Error: 'random error inside'. Error Code: '-32603'",
),
true,
);
},
);
});
});

@ -69,7 +69,7 @@ class ChromeDriver {
for (let i = 0; i < extensions.length; i++) {
const extension = extensions[i].shadowRoot
const name = extension.querySelector('#name').textContent
if (name === "${extensionName}") {
if (name.startsWith("${extensionName}")) {
return extensions[i].getAttribute("id")
}
}

@ -371,7 +371,7 @@ class Driver {
const ignoredLogTypes = ['WARNING'];
const ignoredErrorMessages = [
// Third-party Favicon 404s show up as errors
'favicon.ico - Failed to load resource: the server responded with a status of 404 (Not Found)',
'favicon.ico - Failed to load resource: the server responded with a status of 404',
// Sentry rate limiting
'Failed to load resource: the server responded with a status of 429',
// 4Byte

@ -31,9 +31,10 @@ class FirefoxDriver {
* @param {Object} options - the options for the build
* @param options.responsive
* @param options.port
* @param options.type
* @returns {Promise<{driver: !ThenableWebDriver, extensionUrl: string, extensionId: string}>}
*/
static async build({ responsive, port }) {
static async build({ responsive, port, type }) {
const templateProfile = fs.mkdtempSync(TEMP_PROFILE_PATH_PREFIX);
const options = new firefox.Options().setProfile(templateProfile);
options.setProxy(proxy.manual({ https: HTTPS_PROXY_HOST }));
@ -48,9 +49,13 @@ class FirefoxDriver {
const driver = builder.build();
const fxDriver = new FirefoxDriver(driver);
const extensionId = await fxDriver.installExtension(
`builds/metamask-firefox-${version}.zip`,
);
let extensionString = `builds/metamask-firefox-${version}.zip`;
if (type) {
extensionString = `builds/metamask-${type}-firefox-${version}.zip`;
}
const extensionId = await fxDriver.installExtension(extensionString);
const internalExtensionId = await fxDriver.getInternalId();
if (responsive) {

@ -4,14 +4,14 @@ const Driver = require('./driver');
const ChromeDriver = require('./chrome');
const FirefoxDriver = require('./firefox');
async function buildWebDriver({ responsive, port } = {}) {
async function buildWebDriver({ responsive, port, type } = {}) {
const browser = process.env.SELENIUM_BROWSER;
const {
driver: seleniumDriver,
extensionId,
extensionUrl,
} = await buildBrowserWebDriver(browser, { responsive, port });
} = await buildBrowserWebDriver(browser, { responsive, port, type });
await setupFetchMocking(seleniumDriver);
const driver = new Driver(seleniumDriver, browser, extensionUrl);

@ -43,7 +43,7 @@ export default class PermissionConnect extends Component {
extensionId: PropTypes.string,
iconUrl: PropTypes.string,
name: PropTypes.string,
origin: PropTypes.string.isRequired,
origin: PropTypes.string,
subjectType: PropTypes.string,
}),
isRequestingAccounts: PropTypes.bool.isRequired,

Loading…
Cancel
Save