Skip to content
This repository was archived by the owner on May 5, 2024. It is now read-only.

Commit e38d234

Browse files
authored
Merge pull request #14 from marvinpinto/bundle-errors
Harden the tests to prevent future bundle-related regressions
2 parents 6b7ad92 + 08473e8 commit e38d234

30 files changed

+3243
-227
lines changed

.github/workflows/pre-release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ jobs:
3434

3535
- run: "yarn install --frozen-lockfile"
3636
- run: "yarn lint"
37-
- run: "yarn test"
3837
- run: "yarn build"
38+
- run: "yarn jest --colors --forceExit"
3939

4040
- uses: "./packages/automatic-releases/"
4141
with:

.github/workflows/tagged-release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ jobs:
3232

3333
- run: "yarn install --frozen-lockfile"
3434
- run: "yarn lint"
35-
- run: "yarn test"
3635
- run: "yarn build"
36+
- run: "yarn jest --colors --forceExit"
3737

3838
- uses: "marvinpinto/action-automatic-releases@latest"
3939
with:

.github/workflows/tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ jobs:
3636

3737
- run: "yarn install --frozen-lockfile"
3838
- run: "yarn lint"
39-
- run: "yarn test"
4039
- run: "yarn build"
40+
- run: "yarn jest --colors --forceExit"
4141

4242
- uses: "./packages/keybase-notifications"
4343
if: always()

babel.config.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = {
2+
presets: [
3+
[
4+
'@babel/preset-env',
5+
{
6+
targets: {
7+
node: 'current',
8+
},
9+
},
10+
],
11+
'@babel/preset-typescript',
12+
],
13+
plugins: ['@babel/proposal-class-properties', '@babel/plugin-proposal-optional-chaining'],
14+
};

jest.config.js

+29-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,43 @@
11
module.exports = {
2-
roots: ['<rootDir>/src', '<rootDir>/__tests__'],
32
clearMocks: true,
4-
moduleFileExtensions: ['js', 'ts'],
3+
moduleFileExtensions: ['js', 'ts', 'tsx'],
54
testEnvironment: 'node',
6-
testMatch: ['**/*.test.ts'],
75
testRunner: 'jest-circus/runner',
86
transform: {
9-
'^.+\\.ts$': 'ts-jest',
7+
'^.+\\.ts$': 'babel-jest',
8+
'^.+\\.tsx$': 'babel-jest',
109
},
1110
collectCoverage: true,
12-
projects: ['<rootDir>/packages/*/jest.config.js'],
11+
projects: [
12+
{
13+
name: 'keybase-notifications',
14+
displayName: 'keybase-notifications',
15+
testRegex: 'packages/keybase-notifications/__tests__',
16+
testPathIgnorePatterns: ['/__tests__/payloads', '/__tests__/utils'],
17+
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
18+
},
19+
{
20+
name: 'automatic-releases',
21+
displayName: 'automatic-releases',
22+
testRegex: 'packages/automatic-releases/__tests__',
23+
testPathIgnorePatterns: ['/__tests__/payloads', '/__tests__/utils/', '/__tests__/assets'],
24+
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
25+
},
26+
],
1327
coverageReporters: ['text'],
1428
coverageThreshold: {
1529
global: {
1630
lines: 100,
1731
},
1832
},
19-
setupFilesAfterEnv: ['<rootDir>/../../jest.setup.js'],
33+
collectCoverageFrom: [
34+
'**/packages/keybase-notifications/**/*.ts',
35+
'**/packages/automatic-releases/**/*.ts',
36+
'!**/__tests__/**',
37+
'!**/dist/**',
38+
'!**/packages/keybase-notifications/src/index.ts',
39+
'!**/packages/keybase-notifications/src/utils.ts',
40+
'!**/packages/automatic-releases/src/index.ts',
41+
'!**/packages/automatic-releases/src/uploadReleaseArtifacts.ts',
42+
],
2043
};

package.json

+7-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"prettierPaths": "*.{json,md,yaml,yml} .github/**/*.{json,md,yaml,yml} !package.json !lerna.json"
1717
},
1818
"scripts": {
19-
"test": "lerna run test --stream --no-bail",
19+
"test": "yarn jest --colors",
2020
"build": "lerna run build --stream",
2121
"clean": "lerna run clean --stream && rm -rf node_modules yarn-error.log",
2222
"reinstall": "yarn clean; yarn install",
@@ -30,14 +30,19 @@
3030
"release": "lerna version"
3131
},
3232
"devDependencies": {
33+
"@babel/core": "^7.7.7",
34+
"@babel/plugin-proposal-class-properties": "^7.7.4",
35+
"@babel/plugin-proposal-optional-chaining": "^7.7.5",
36+
"@babel/preset-env": "^7.7.7",
37+
"@babel/preset-typescript": "^7.7.7",
3338
"@commitlint/cli": "^8.2.0",
3439
"@commitlint/config-conventional": "^8.2.0",
3540
"@commitlint/config-lerna-scopes": "^8.2.0",
3641
"@types/jest": "^24.0.24",
3742
"@types/node": "^13.1.0",
3843
"@typescript-eslint/eslint-plugin": "^2.13.0",
3944
"@typescript-eslint/parser": "^2.13.0",
40-
"@zeit/ncc": "^0.20.5",
45+
"babel-jest": "^24.9.0",
4146
"eslint": "^6.8.0",
4247
"eslint-config-prettier": "^6.8.0",
4348
"eslint-plugin-jest": "^23.1.1",
@@ -46,7 +51,6 @@
4651
"jest-circus": "^24.9.0",
4752
"lerna": "^3.19.0",
4853
"prettier": "^1.19.1",
49-
"ts-jest": "^24.2.0",
5054
"typescript": "^3.7.4"
5155
},
5256
"eslintIgnore": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import skipSmokeTestsLocally from './utils/skipSmoke';
2+
import util from 'util';
3+
import child_process from 'child_process';
4+
import path from 'path';
5+
import fs from 'fs';
6+
import os from 'os';
7+
import portfinder from 'portfinder';
8+
import * as mockNewReleaseTag from './utils/mockNewReleaseTag';
9+
import * as mockUpdateExistingTag from './utils/mockUpdateExistingTag';
10+
import which from 'which';
11+
12+
const exec = util.promisify(child_process.exec)
13+
14+
describe('automatic releases smoke tests', () => {
15+
skipSmokeTestsLocally();
16+
const distBundle = path.join(__dirname, '../dist', 'index.js');
17+
18+
const sanitizeEnvironment = async () => {
19+
const bundlePath = path.join(__dirname, '../dist');
20+
const tdir = fs.mkdtempSync(path.join(os.tmpdir(), 'ghactions-'));
21+
await exec(`cp ${bundlePath}/* ${tdir}/`);
22+
return path.join(tdir, 'index.js');
23+
};
24+
25+
it('should create a new release tag', async (cb) => {
26+
const httpPort = await portfinder.getPortPromise();
27+
const mockHttp = mockNewReleaseTag.server.listen(httpPort);
28+
const bundle = await sanitizeEnvironment();
29+
30+
const node = which.sync('node')
31+
const {stdout, stderr} = await exec(`${node} ${bundle}`, {
32+
cwd: os.tmpdir(),
33+
env: {
34+
...mockNewReleaseTag.setupEnv,
35+
JEST_MOCK_HTTP_PORT: JSON.stringify(httpPort),
36+
AUTOMATIC_RELEASES_TAG: '',
37+
},
38+
});
39+
40+
// Should set the AUTOMATIC_RELEASES_TAG env variable to "testingtaglatest"
41+
expect(stdout).toEqual(expect.stringMatching(/::set-env name=AUTOMATIC_RELEASES_TAG,::testingtaglatest/));
42+
43+
// There should not be any stderr output
44+
expect(stderr).toEqual('');
45+
46+
mockHttp.close(cb);
47+
});
48+
49+
it('should update an existing release tag', async (cb) => {
50+
const httpPort = await portfinder.getPortPromise();
51+
const mockHttp = mockUpdateExistingTag.server.listen(httpPort);
52+
const bundle = await sanitizeEnvironment();
53+
54+
const node = which.sync('node')
55+
const {stdout, stderr} = await exec(`${node} ${bundle}`, {
56+
cwd: os.tmpdir(),
57+
env: {
58+
...mockUpdateExistingTag.setupEnv,
59+
JEST_MOCK_HTTP_PORT: JSON.stringify(httpPort),
60+
AUTOMATIC_RELEASES_TAG: '',
61+
},
62+
});
63+
64+
// Should set the AUTOMATIC_RELEASES_TAG env variable to "testingtaglatest"
65+
expect(stdout).toEqual(expect.stringMatching(/::set-env name=AUTOMATIC_RELEASES_TAG,::testingtaglatest/));
66+
67+
// There should not be any stderr output
68+
expect(stderr).toEqual('');
69+
70+
mockHttp.close(cb);
71+
});
72+
});

packages/automatic-releases/__tests__/automaticReleases.test.ts

+21-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
/* eslint-disable @typescript-eslint/no-var-requires */
2-
31
import * as process from 'process';
42
import * as path from 'path';
53
import nock from 'nock';
64
import fs from 'fs';
5+
import {uploadReleaseArtifacts} from '../src/uploadReleaseArtifacts';
6+
import {main} from '../src/main';
7+
8+
jest.mock('../src/uploadReleaseArtifacts');
79

810
describe('main handler processing automatic releases', () => {
911
const testGhToken = 'fake-secret-token';
@@ -33,6 +35,8 @@ describe('main handler processing automatic releases', () => {
3335
process.env['GITHUB_ACTOR'] = 'marvinpinto';
3436
process.env['GITHUB_EVENT_PATH'] = path.join(__dirname, 'payloads', 'git-push.json');
3537
process.env['GITHUB_REPOSITORY'] = 'marvinpinto/private-actions-tester';
38+
39+
uploadReleaseArtifacts.mockImplementation().mockResolvedValue({});
3640
});
3741

3842
afterEach(() => {
@@ -44,8 +48,7 @@ describe('main handler processing automatic releases', () => {
4448

4549
it('throws an error when "automatic_release_tag" is not supplied', async () => {
4650
delete process.env.INPUT_AUTOMATIC_RELEASE_TAG;
47-
const inst = require('../src/main');
48-
await expect(inst.main()).rejects.toThrow(
51+
await expect(main()).rejects.toThrow(
4952
'The parameter "automatic_release_tag" was not set and this does not appear to be a GitHub tag event. (Event: refs/heads/automatic-pre-releaser)',
5053
);
5154
});
@@ -62,6 +65,11 @@ describe('main handler processing automatic releases', () => {
6265
.get(`/repos/marvinpinto/private-actions-tester/compare/HEAD...${testGhSHA}`)
6366
.reply(200, compareCommitsPayload);
6467

68+
const getRef = nock('https://api.github.com')
69+
.matchHeader('authorization', `token ${testGhToken}`)
70+
.get(`/repos/marvinpinto/private-actions-tester/git/refs/tags/${testInputAutomaticReleaseTag}`)
71+
.reply(404);
72+
6573
const listAssociatedPRs = nock('https://api.github.com')
6674
.matchHeader('authorization', `token ${testGhToken}`)
6775
.get(`/repos/marvinpinto/private-actions-tester/commits/${testGhSHA}/pulls`)
@@ -101,21 +109,20 @@ describe('main handler processing automatic releases', () => {
101109
// Output env variable should be empty
102110
expect(process.env['AUTOMATIC_RELEASES_TAG']).toBeUndefined();
103111

104-
const inst = require('../src/main');
105-
inst.uploadReleaseArtifacts = jest.fn(() => Promise.resolve());
106-
await inst.main();
112+
await main();
107113

108114
expect(createRef.isDone()).toBe(true);
109115
expect(getReleaseByTag.isDone()).toBe(true);
110116
expect(deleteRelease.isDone()).toBe(false);
111117
expect(createRelease.isDone()).toBe(true);
118+
expect(getRef.isDone()).toBe(true);
112119
expect(getCommitsSinceRelease.isDone()).toBe(true);
113120
expect(listAssociatedPRs.isDone()).toBe(true);
114121

115-
expect(inst.uploadReleaseArtifacts).toHaveBeenCalledTimes(1);
116-
expect(inst.uploadReleaseArtifacts.mock.calls[0][1]).toBe(releaseUploadUrl);
122+
expect(uploadReleaseArtifacts).toHaveBeenCalledTimes(1);
123+
expect(uploadReleaseArtifacts.mock.calls[0][1]).toBe(releaseUploadUrl);
117124
// Should not attempt to upload any release artifacts, as there are none
118-
expect(inst.uploadReleaseArtifacts.mock.calls[0][2]).toEqual([]);
125+
expect(uploadReleaseArtifacts.mock.calls[0][2]).toEqual([]);
119126

120127
// Should populate the output env variable
121128
expect(process.env['AUTOMATIC_RELEASES_TAG']).toBe(testInputAutomaticReleaseTag);
@@ -193,9 +200,7 @@ describe('main handler processing automatic releases', () => {
193200
// Output env variable should be empty
194201
expect(process.env['AUTOMATIC_RELEASES_TAG']).toBeUndefined();
195202

196-
const inst = require('../src/main');
197-
inst.uploadReleaseArtifacts = jest.fn(() => Promise.resolve());
198-
await inst.main();
203+
await main();
199204

200205
expect(createRef.isDone()).toBe(true);
201206
expect(updateRef.isDone()).toBe(true);
@@ -206,9 +211,9 @@ describe('main handler processing automatic releases', () => {
206211
expect(getCommitsSinceRelease.isDone()).toBe(true);
207212
expect(listAssociatedPRs.isDone()).toBe(true);
208213

209-
expect(inst.uploadReleaseArtifacts).toHaveBeenCalledTimes(1);
210-
expect(inst.uploadReleaseArtifacts.mock.calls[0][1]).toBe(releaseUploadUrl);
211-
expect(inst.uploadReleaseArtifacts.mock.calls[0][2]).toEqual(['file1.txt', 'file2.txt', '*.jar']);
214+
expect(uploadReleaseArtifacts).toHaveBeenCalledTimes(1);
215+
expect(uploadReleaseArtifacts.mock.calls[0][1]).toBe(releaseUploadUrl);
216+
expect(uploadReleaseArtifacts.mock.calls[0][2]).toEqual(['file1.txt', 'file2.txt', '*.jar']);
212217

213218
// Should populate the output env variable
214219
expect(process.env['AUTOMATIC_RELEASES_TAG']).toBe(testInputAutomaticReleaseTag);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import skipSmokeTestsLocally from './utils/skipSmoke';
2+
import util from 'util';
3+
import child_process from 'child_process';
4+
import path from 'path';
5+
import fs from 'fs';
6+
import os from 'os';
7+
import portfinder from 'portfinder';
8+
import * as mockNewTaggedRelease from './utils/mockNewTaggedRelease';
9+
import which from 'which';
10+
11+
const exec = util.promisify(child_process.exec)
12+
13+
describe('tagged releases smoke tests', () => {
14+
skipSmokeTestsLocally();
15+
const distBundle = path.join(__dirname, '../dist', 'index.js');
16+
17+
const sanitizeEnvironment = async () => {
18+
const bundlePath = path.join(__dirname, '../dist');
19+
const tdir = fs.mkdtempSync(path.join(os.tmpdir(), 'ghactions-'));
20+
await exec(`cp ${bundlePath}/* ${tdir}/`);
21+
return path.join(tdir, 'index.js');
22+
};
23+
24+
it('should create a new release', async (cb) => {
25+
const httpPort = await portfinder.getPortPromise();
26+
const mockHttp = mockNewTaggedRelease.server.listen(httpPort);
27+
const bundle = await sanitizeEnvironment();
28+
29+
const node = which.sync('node')
30+
const {stdout, stderr} = await exec(`${node} ${bundle}`, {
31+
cwd: os.tmpdir(),
32+
env: {
33+
...mockNewTaggedRelease.setupEnv,
34+
JEST_MOCK_HTTP_PORT: JSON.stringify(httpPort),
35+
AUTOMATIC_RELEASES_TAG: '',
36+
},
37+
});
38+
39+
// Should set the AUTOMATIC_RELEASES_TAG env variable to "v0.0.1"
40+
expect(stdout).toEqual(expect.stringMatching(/::set-env name=AUTOMATIC_RELEASES_TAG,::v0.0.1/));
41+
42+
// There should not be any stderr output
43+
expect(stderr).toEqual('');
44+
45+
mockHttp.close(cb);
46+
});
47+
});

0 commit comments

Comments
 (0)