Skip to content

Commit

Permalink
Finish first e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
mrruby committed Jun 28, 2024
1 parent e2c7902 commit aa614dd
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 16 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/client-PR.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: 'client-pr'
on:
pull_request:
branches: [main]
paths:
- 'holo-key-manager-js-client/package.json'
- '.github/workflows/client.yaml'

jobs:
build:
runs-on: ubuntu-latest

environment:
name: Client

steps:
- uses: actions/checkout@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: lts/*
registry-url: 'https://registry.npmjs.org'
- name: Install pnpm
run: npm install -g pnpm
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
working-directory: holo-key-manager-js-client
- name: Run unit tests
run: pnpm test
working-directory: holo-key-manager-js-client
2 changes: 1 addition & 1 deletion .github/workflows/client.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 20
node-version: lts/*
registry-url: 'https://registry.npmjs.org'
- name: Install pnpm
run: npm install -g pnpm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/extension-PR.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 20
node-version: lts/*

- name: Install pnpm
run: npm install -g pnpm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/extension.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 20
node-version: lts/*

- name: Install pnpm
run: npm install -g pnpm
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"eslint-plugin-svelte": "^2.39.3",
"globals": "^15.4.0",
"husky": "^9.0.11",
"jszip": "^3.10.1",
"lint-staged": "^15.2.5",
"prettier": "^3.3.2",
"puppeteer": "^22.12.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 33 additions & 10 deletions tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { access, constants } from 'fs';
import { Browser, ElementHandle, launch, Page } from 'puppeteer';

export const launchBrowserWithExtension = async (extensionPath: string): Promise<Browser> => {
Expand All @@ -13,21 +14,43 @@ export const openExtensionPage = async (browser: Browser, extensionId: string):
return page;
};

const waitForNewPage = (browser: Browser): Promise<Page> =>
new Promise((resolve, reject) =>
browser.once('targetcreated', async (target) => {
const page = await target.page();
page ? resolve(page) : reject(new Error('Failed to create new page'));
})
);

export const clickButtonAndWaitForNewPage = async (
browser: Browser,
button: ElementHandle<Element>
button: ElementHandle<Element>,
downloadPath: string
): Promise<Page> => {
await button?.click();

const newPagePromise = new Promise<Page | null>((resolve) =>
browser.once('targetcreated', async (target) => resolve(await target.page()))
);

const newPage = await newPagePromise;
if (!newPage) {
throw new Error('Failed to create new page');
}
const newPage = await waitForNewPage(browser);
await newPage.waitForNavigation();

const session = await newPage.createCDPSession();
await session.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: downloadPath
});

return newPage;
};

export const fileExists = (filePath: string): Promise<boolean> => {
return new Promise((resolve) => {
const checkFile = () => {
access(filePath, constants.F_OK, (err) => {
if (!err) {
resolve(true);
} else {
setTimeout(checkFile, 100);
}
});
};
checkFile();
});
};
99 changes: 96 additions & 3 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import dotenv from 'dotenv';
import path from 'path';
import { rmdirSync } from 'fs';
import fs from 'fs/promises';
import JSZip from 'jszip';
import { join, resolve } from 'path';
import type { Browser, Page } from 'puppeteer';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import {
clickButtonAndWaitForNewPage,
fileExists,
launchBrowserWithExtension,
openExtensionPage
} from './helpers';
Expand All @@ -13,19 +17,22 @@ dotenv.config();

const EXTENSION_ID = process.env.CHROME_ID;

const downloadPath = resolve('./downloads');

let browser: Browser;
let page: Page;

beforeAll(async () => {
if (!EXTENSION_ID) {
throw new Error('EXTENSION_ID is not set');
}
const extensionPath = path.resolve('holo-key-manager-extension', 'build');
const extensionPath = resolve('holo-key-manager-extension', 'build');
browser = await launchBrowserWithExtension(extensionPath);
page = await openExtensionPage(browser, EXTENSION_ID);
});

afterAll(async () => {
rmdirSync(downloadPath, { recursive: true });

Check failure on line 35 in tests/index.test.ts

View workflow job for this annotation

GitHub Actions / build

tests/index.test.ts

Error: ENOENT: no such file or directory, lstat '/home/runner/work/holo-key-manager/holo-key-manager/downloads' ❯ Proxy.rmdirSync node:fs:1206:15 ❯ tests/index.test.ts:35:2 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { errno: -2, code: 'ENOENT', syscall: 'lstat', path: '/home/runner/work/holo-key-manager/holo-key-manager/downloads' }
await browser?.close();
});

Expand All @@ -38,7 +45,8 @@ describe('Extension E2E Tests', () => {
if (!setupButton) {
throw new Error('Button not found');
}
const setupPage = await clickButtonAndWaitForNewPage(browser, setupButton);

const setupPage = await clickButtonAndWaitForNewPage(browser, setupButton, downloadPath);

const setupPageContent = await setupPage.content();

Expand Down Expand Up @@ -81,5 +89,90 @@ describe('Extension E2E Tests', () => {
const enterPassphrasePageContent = await setupPage.content();

expect(enterPassphrasePageContent).toContain('Enter Passphrase');

const enterPassphraseInput = await setupPage.waitForSelector(
'textarea[placeholder="Enter Passphrase"]'
);
if (!enterPassphraseInput) {
throw new Error('Password inputs not found');
}

await enterPassphraseInput.type('passphrase passphrase');

const setPassphraseButton = await setupPage.waitForSelector(
'button::-p-text("Set passphrase")'
);

if (!setPassphraseButton) {
throw new Error('Button not found');
}

await setPassphraseButton.click();

const confirmPassphrasePageContent = await setupPage.content();

expect(confirmPassphrasePageContent).toContain('Confirm Passphrase');

const confirmPassphraseInput = await setupPage.waitForSelector(
'textarea[placeholder="Confirm Passphrase"]'
);

if (!confirmPassphraseInput) {
throw new Error('Password inputs not found');
}

await confirmPassphraseInput.type('passphrase passphrase');

const confirmPassphraseButton = await setupPage.waitForSelector('button::-p-text("Next")');

if (!confirmPassphraseButton) {
throw new Error('Button not found');
}

await Promise.all([setupPage.waitForNavigation(), confirmPassphraseButton.click()]);

const generateSeedPageContent = await setupPage.content();

expect(generateSeedPageContent).toContain('Generate seed and key files');

const generateButton = await setupPage.waitForSelector('button::-p-text("Generate")');

if (!generateButton) {
throw new Error('Button not found');
}

await Promise.all([setupPage.waitForNavigation(), generateButton.click()]);

const saveSeedPageContent = await setupPage.content();

expect(saveSeedPageContent).toContain('Save seed and key files');

const exportButton = await setupPage.waitForSelector('button::-p-text("Export")');

if (!exportButton) {
throw new Error('Button not found');
}

exportButton.click();

const keysFilePath = join(downloadPath, 'keys.zip');

const keysFileExists = await fileExists(keysFilePath);

expect(keysFileExists).toBe(true);

const zipContent = await fs.readFile(keysFilePath);
const zip = await JSZip.loadAsync(zipContent);

const expectedFiles = ['device.txt', 'master.txt', 'revocation.txt'];
const actualFiles = Object.keys(zip.files);

expectedFiles.forEach((file) => {
expect(actualFiles).toContain(file);
});

const setupCompletePageContent = await setupPage.content();

expect(setupCompletePageContent).toContain('Setup Complete');
}, 10000);
});

0 comments on commit aa614dd

Please sign in to comment.