mirror of
https://github.com/morten-olsen/parcel.git
synced 2026-02-08 01:36:24 +01:00
feat: Add E2E tests (#4)
This commit is contained in:
20
.github/workflows/qa.yml
vendored
Normal file
20
.github/workflows/qa.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: QA
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout 🛎️
|
||||||
|
uses: actions/checkout@v2.3.1 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Install 🔧
|
||||||
|
run: |
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
yarn test
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN PGP MESSAGE-----
|
||||||
|
Version: OpenPGP.js v4.10.7
|
||||||
|
Comment: https://openpgpjs.org
|
||||||
|
|
||||||
|
wcDMAwd2QSi0rCknAQv/TOSkfzJeI4QeOGhTnPPH1Dbc0lXfJJFO/7k+hEaU
|
||||||
|
nuj2ZETCJGBfTlktMdDq6pHcdXh1oLRW6mWxzBugspmJc1Hw7953+7oas0OF
|
||||||
|
jf4k8Jwg87AQcea38t8pJYvfhKQe7qXR3aqnXCzb0PYzTloBsM+/S3j+qYsT
|
||||||
|
TlDeN8LZfrGpBheGhiFI+XXIfbUSYNekIayj+u/HOiTNY4WCQKji44BC//oA
|
||||||
|
IGKKyMLTBNjr86qYZF6Cowph4XMs9HhDP7OowPShdvArk2gvdELGD23Ywp1w
|
||||||
|
2f6v6PUg8nSzleeETwnxLA3LKZZOz0/JYf30Q9gFr6uHf3tF510iO+KicjvS
|
||||||
|
Y+OQ7k800ZFsLKdEy0bWySNUYyb9lycaOofR8Xm5GP0bs8/T6IoS4x6ii342
|
||||||
|
dP/GcfRqLPbhM5LK9hbLpHRgpWyZsi+Or8Oyky6sPEvhFuecCPBb25Qju8ul
|
||||||
|
VXfvIZqShw8pE1irbZlGQbFTq3yv8W2Ullu/QBwivDv1nL2bhocl0jsBFkSS
|
||||||
|
qNqruW5Pim0exfz3HcnPvWxRxaolalGSRebb/MPcOz+ypw8wl3yuU+tLtNFK
|
||||||
|
tfRdoo5leF334g==
|
||||||
|
=gbKf
|
||||||
|
-----END PGP MESSAGE-----
|
||||||
7
jest.config.js
Normal file
7
jest.config.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testEnvironment: path.join(__dirname, 'tests', 'env.js'),
|
||||||
|
};
|
||||||
13
package.json
13
package.json
@@ -4,7 +4,8 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack"
|
"build": "webpack",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ant-design/icons": "^4.2.2",
|
"@ant-design/icons": "^4.2.2",
|
||||||
@@ -13,7 +14,11 @@
|
|||||||
"@babel/preset-react": "^7.10.4",
|
"@babel/preset-react": "^7.10.4",
|
||||||
"@babel/preset-typescript": "^7.10.4",
|
"@babel/preset-typescript": "^7.10.4",
|
||||||
"@hot-loader/react-dom": "^16.13.0",
|
"@hot-loader/react-dom": "^16.13.0",
|
||||||
|
"@types/express": "^4.17.11",
|
||||||
|
"@types/fs-extra": "^9.0.7",
|
||||||
|
"@types/get-port": "^4.2.0",
|
||||||
"@types/html-webpack-plugin": "^3.2.3",
|
"@types/html-webpack-plugin": "^3.2.3",
|
||||||
|
"@types/jest": "^26.0.20",
|
||||||
"@types/jszip": "^3.4.1",
|
"@types/jszip": "^3.4.1",
|
||||||
"@types/openpgp": "^4.4.12",
|
"@types/openpgp": "^4.4.12",
|
||||||
"@types/react": "^16.9.46",
|
"@types/react": "^16.9.46",
|
||||||
@@ -29,11 +34,17 @@
|
|||||||
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
|
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
|
||||||
"css-loader": "^4.2.1",
|
"css-loader": "^4.2.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"fs-extra": "^9.1.0",
|
||||||
|
"get-port": "^5.1.1",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
|
"jest": "^26.6.3",
|
||||||
"offline-plugin": "^5.0.7",
|
"offline-plugin": "^5.0.7",
|
||||||
"parcel-bundler": "^1.12.4",
|
"parcel-bundler": "^1.12.4",
|
||||||
|
"puppeteer": "^7.1.0",
|
||||||
"react-hot-loader": "^4.12.21",
|
"react-hot-loader": "^4.12.21",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^1.2.1",
|
||||||
|
"ts-jest": "^26.5.1",
|
||||||
"ts-node": "^8.10.2",
|
"ts-node": "^8.10.2",
|
||||||
"typescript": "^3.9.7",
|
"typescript": "^3.9.7",
|
||||||
"webpack": "^4.44.1",
|
"webpack": "^4.44.1",
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ const FileView: React.FC<Props> = ({
|
|||||||
actions.push(
|
actions.push(
|
||||||
<IconText
|
<IconText
|
||||||
icon={DownloadOutlined}
|
icon={DownloadOutlined}
|
||||||
|
className="msg-download"
|
||||||
type="primary"
|
type="primary"
|
||||||
text="Download"
|
text="Download"
|
||||||
onClick={() => downloadLink(file.name, file.blob!)}
|
onClick={() => downloadLink(file.name, file.blob!)}
|
||||||
@@ -77,6 +78,7 @@ const FileView: React.FC<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<List.Item
|
<List.Item
|
||||||
actions={actions}
|
actions={actions}
|
||||||
|
className="msg-item"
|
||||||
>
|
>
|
||||||
<List.Item.Meta
|
<List.Item.Meta
|
||||||
avatar={icon}
|
avatar={icon}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ const Add: React.FC = () => {
|
|||||||
<>
|
<>
|
||||||
<Divider>
|
<Divider>
|
||||||
<Radio.Group onChange={evt => setType(evt.target.value)} defaultValue={DEFAULT_VALUE}>
|
<Radio.Group onChange={evt => setType(evt.target.value)} defaultValue={DEFAULT_VALUE}>
|
||||||
<Radio.Button value="text"><FileTextOutlined /> Text</Radio.Button>
|
<Radio.Button className="add-text-tab" value="text"><FileTextOutlined /> Text</Radio.Button>
|
||||||
<Radio.Button value="file"><FileOutlined /> File</Radio.Button>
|
<Radio.Button className="add-file-tab" value="file"><FileOutlined /> File</Radio.Button>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Divider>
|
</Divider>
|
||||||
{type === 'text' && <AddText />}
|
{type === 'text' && <AddText />}
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ const AddText : React.FC = () => {
|
|||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Title"
|
placeholder="Title"
|
||||||
|
className="msg-title"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={evt => setName(evt.target.value)}
|
onChange={evt => setName(evt.target.value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
|
className="msg-body"
|
||||||
placeholder="Your message here..."
|
placeholder="Your message here..."
|
||||||
value={text}
|
value={text}
|
||||||
rows={6}
|
rows={6}
|
||||||
@@ -34,6 +36,7 @@ const AddText : React.FC = () => {
|
|||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Button
|
<Button
|
||||||
onClick={add}
|
onClick={add}
|
||||||
|
className="msg-add"
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
disabled={!text}
|
disabled={!text}
|
||||||
|
|||||||
1
src/global.d.ts
vendored
Normal file
1
src/global.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
declare var testUrl: string;
|
||||||
@@ -16,6 +16,7 @@ const Thumb: React.FC = ({
|
|||||||
title,
|
title,
|
||||||
Icon,
|
Icon,
|
||||||
link,
|
link,
|
||||||
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
return (
|
return (
|
||||||
@@ -23,6 +24,7 @@ const Thumb: React.FC = ({
|
|||||||
size="large"
|
size="large"
|
||||||
icon={<Icon />}
|
icon={<Icon />}
|
||||||
type="link"
|
type="link"
|
||||||
|
className={className}
|
||||||
onClick={() => history.push(link)}
|
onClick={() => history.push(link)}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
@@ -39,15 +41,18 @@ const Intro = () => {
|
|||||||
<Thumb
|
<Thumb
|
||||||
title="I want to send a text/file"
|
title="I want to send a text/file"
|
||||||
link="/send"
|
link="/send"
|
||||||
|
className="send-btn"
|
||||||
Icon={UploadOutlined}
|
Icon={UploadOutlined}
|
||||||
/>
|
/>
|
||||||
<Thumb
|
<Thumb
|
||||||
link="/key"
|
link="/key"
|
||||||
|
className="want-to-receive-btn"
|
||||||
title="I want to receive a file"
|
title="I want to receive a file"
|
||||||
Icon={KeyOutlined}
|
Icon={KeyOutlined}
|
||||||
/>
|
/>
|
||||||
<Thumb
|
<Thumb
|
||||||
link="/receive"
|
link="/receive"
|
||||||
|
className="did-receive-btn"
|
||||||
title="I have received a file"
|
title="I have received a file"
|
||||||
Icon={DownloadOutlined}
|
Icon={DownloadOutlined}
|
||||||
/>
|
/>
|
||||||
|
|||||||
81
test-assets/key
Normal file
81
test-assets/key
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
9R+pJKNnVhsIEwEn
|
||||||
|
=elvE
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
40
test-assets/key.pub
Normal file
40
test-assets/key.pub
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=dEQO
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
76
tests/encryption.test.ts
Normal file
76
tests/encryption.test.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import puppeteer, { Browser, Page } from 'puppeteer';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import { nanoid } from 'nanoid';
|
||||||
|
import openpgp, { key, message } from 'openpgp';
|
||||||
|
|
||||||
|
const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time));
|
||||||
|
|
||||||
|
describe('encryption', () => {
|
||||||
|
let browser: Browser;
|
||||||
|
let page: Page;
|
||||||
|
let tmpDir: string;
|
||||||
|
let keys: key.KeyResult;
|
||||||
|
|
||||||
|
const getText = async (elm: any) => {
|
||||||
|
const text = await page.evaluate(el => el.textContent, elm);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
tmpDir = path.resolve(`.tmp/${nanoid}`);
|
||||||
|
await fs.mkdirp(tmpDir);
|
||||||
|
const data = await fs.readFile(
|
||||||
|
path.join(__dirname, '..', 'test-assets', 'key'),
|
||||||
|
'utf-8',
|
||||||
|
);
|
||||||
|
keys = await key.readArmored(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
browser = await puppeteer.launch({
|
||||||
|
args: [
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-setuid-sandbox',
|
||||||
|
]
|
||||||
|
});
|
||||||
|
page = await browser.newPage();
|
||||||
|
(page as any)._client.send('Page.setDownloadBehavior', {
|
||||||
|
behavior: 'allow',
|
||||||
|
downloadPath: tmpDir,
|
||||||
|
});
|
||||||
|
await page.goto(testUrl, {
|
||||||
|
waitUntil: 'networkidle2',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to encrypt a text', async () => {
|
||||||
|
await page.click('.send-btn');
|
||||||
|
await page.click('.add-text-tab');
|
||||||
|
await page.type('.msg-title', 'Foo');
|
||||||
|
await page.type('.msg-body', 'Bar');
|
||||||
|
await page.click('.msg-add');
|
||||||
|
await sleep(300);
|
||||||
|
const items = await page.$$('.msg-item');
|
||||||
|
expect(items.length).toBe(1);
|
||||||
|
const [item] = items;
|
||||||
|
const title = await item.$('.ant-list-item-meta-title');
|
||||||
|
const titleText = await getText(title);
|
||||||
|
expect(titleText).toBe('Foo.txt.asc');
|
||||||
|
await page.click('.msg-download');
|
||||||
|
await sleep(300);
|
||||||
|
const downloadPath = path.join(tmpDir, 'Foo.txt.asc');
|
||||||
|
expect(fs.existsSync(downloadPath)).toBe(true);
|
||||||
|
const data = await fs.readFile(downloadPath, 'utf-8');
|
||||||
|
|
||||||
|
const decrypted = await openpgp.decrypt({
|
||||||
|
message: await message.readArmored(data),
|
||||||
|
privateKeys: keys.keys[0],
|
||||||
|
});
|
||||||
|
expect(decrypted.data).toBe('Bar');
|
||||||
|
});
|
||||||
|
});
|
||||||
50
tests/env-ts.ts
Normal file
50
tests/env-ts.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import NodeEnvironment from 'jest-environment-node';
|
||||||
|
import { Server, createServer } from 'http';
|
||||||
|
import getPort from 'get-port';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import path from 'path';
|
||||||
|
import express from 'express';
|
||||||
|
import createConfig from '../webpack.config';
|
||||||
|
|
||||||
|
const build = () => new Promise<Server>(async (resolve, reject) => {
|
||||||
|
const config = await createConfig({
|
||||||
|
test: true,
|
||||||
|
});
|
||||||
|
const port = await getPort();
|
||||||
|
const bundler = webpack(config);
|
||||||
|
bundler.run((err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
} else if (stats.hasErrors()) {
|
||||||
|
return reject(new Error('Webpack errors'));
|
||||||
|
}
|
||||||
|
const app = express();
|
||||||
|
app.use(express.static(path.join(__dirname, '..', 'dist')));
|
||||||
|
const server = createServer(app);
|
||||||
|
const listener = server.listen(port, '127.0.0.1', () => {
|
||||||
|
resolve(listener);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
class CustomEnvironment extends NodeEnvironment {
|
||||||
|
private _server?: Server;
|
||||||
|
|
||||||
|
constructor(config: any) {
|
||||||
|
super(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setup() {
|
||||||
|
await super.setup();
|
||||||
|
this._server = await build();
|
||||||
|
const address: any = this._server?.address();
|
||||||
|
this.global.testUrl = `http://${address.address}:${address.port}`
|
||||||
|
}
|
||||||
|
|
||||||
|
async teardown() {
|
||||||
|
await super.teardown();
|
||||||
|
this._server?.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CustomEnvironment;
|
||||||
4
tests/env.js
Normal file
4
tests/env.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
require('ts-node/register');
|
||||||
|
const Env = require('./env-ts');
|
||||||
|
|
||||||
|
module.exports = Env;
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
import webpack, { Configuration } from 'webpack';
|
import webpack, { Configuration } from 'webpack';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import fs from 'fs';
|
||||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
import WorkboxWebpackPlugin from 'workbox-webpack-plugin';
|
import WorkboxWebpackPlugin from 'workbox-webpack-plugin';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
test: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const repo = process.env.GITHUB_REPOSITORY;
|
const repo = process.env.GITHUB_REPOSITORY;
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
throw new Error('No GITHUB_REPOSITRY env variable found');
|
throw new Error('No GITHUB_REPOSITRY env variable found');
|
||||||
@@ -13,7 +18,7 @@ const [username] = repo.split('/');
|
|||||||
|
|
||||||
const __DEV__ = process.env.NODE_ENV !== 'production';
|
const __DEV__ = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
const createConfig = async ():Promise<Configuration> => {
|
const getData = async () => {
|
||||||
const { data: keyList } = await axios.get(`https://api.github.com/users/${username}/gpg_keys`);
|
const { data: keyList } = await axios.get(`https://api.github.com/users/${username}/gpg_keys`);
|
||||||
if (keyList.length === 0) {
|
if (keyList.length === 0) {
|
||||||
throw new Error(`The user ${username} does not have any GPG keys`);
|
throw new Error(`The user ${username} does not have any GPG keys`);
|
||||||
@@ -22,6 +27,24 @@ const createConfig = async ():Promise<Configuration> => {
|
|||||||
username,
|
username,
|
||||||
keys: keyList.map((key: any) => key.raw_key),
|
keys: keyList.map((key: any) => key.raw_key),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTestData: typeof getData = async () => {
|
||||||
|
const pubKey = fs.readFileSync(path.join(__dirname, 'test-assets', 'key.pub'), 'utf-8');
|
||||||
|
return {
|
||||||
|
username: 'foobar',
|
||||||
|
keys: [
|
||||||
|
pubKey,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const createConfig = async (options: Options = {
|
||||||
|
test: false,
|
||||||
|
}):Promise<Configuration> => {
|
||||||
|
const data = await (options.test ? getTestData() : getData());
|
||||||
const config: Configuration = {
|
const config: Configuration = {
|
||||||
mode: __DEV__ ? 'development' : 'production',
|
mode: __DEV__ ? 'development' : 'production',
|
||||||
entry: {
|
entry: {
|
||||||
|
|||||||
Reference in New Issue
Block a user