Skip to content

Commit

Permalink
πŸ’š Add Windows workflow (#176)
Browse files Browse the repository at this point in the history
* πŸ‘· Add Windows CI workflow

* πŸ”¨ Fix Windows babel registration

* βœ… Fix cli-config tests for Windows

* βœ… Fix config tests for Windows

* πŸ”‡ Ignore rimraf errors on tmp cleanup

* ⬆ Upgrade interactor.js from 2.0.0-beta.9 to 2.0.0-beta.10

* βœ… Remove explicit browser install test

This script must work for any tests to work. Since it is technically tested by running before tests,
it does not generate coverage. In order to generate coverage, the existing browser install directory
is deleted within the test. This causes issues on Windows and actually makes the test suite slower
overall. Removing the test solves the issue on Windows, speeds up the test suite, and is still
required to work for almost any tests.

* βœ… Use platform agnostic command for exec tests

* πŸ› End browser process pipes during cleanup

This is needed specifically for Windows
  • Loading branch information
Wil Wilsman authored Feb 23, 2021
1 parent 47bc76a commit d168ffb
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 58 deletions.
67 changes: 67 additions & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Windows
on: push
jobs:
build:
name: Build
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: v1/${{ runner.os }}/node-12/${{ hashFiles('**/yarn.lock') }}
restore-keys: v1/${{ runner.os }}/node-12/
- run: yarn
- run: yarn build
- uses: actions/upload-artifact@v2
with:
name: dist
path: packages/*/dist

test:
name: Test ${{ matrix.package }}
needs: [build]
strategy:
matrix:
package:
- '@percy/env'
- '@percy/client'
- '@percy/dom'
- '@percy/logger'
- '@percy/config'
- '@percy/core'
- '@percy/cli'
- '@percy/cli-command'
- '@percy/cli-exec'
- '@percy/cli-snapshot'
- '@percy/cli-upload'
- '@percy/cli-build'
- '@percy/cli-config'
- '@percy/sdk-utils'
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: v1/${{ runner.os }}/node-12/${{ hashFiles('**/yarn.lock') }}
restore-keys: v1/${{ runner.os }}/node-12/
- uses: actions/download-artifact@v2
with:
name: dist
path: packages
- run: yarn
- name: Run tests
run: yarn workspace ${{ matrix.package }} test --colors
11 changes: 7 additions & 4 deletions packages/cli-config/test/create.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import path from 'path';
import expect from 'expect';
import { logger, getMockConfig } from './helpers';
import { Create } from '../src/commands/config/create';
Expand Down Expand Up @@ -47,14 +48,16 @@ describe('percy config:create', () => {
});

it('can create specific config files', async () => {
await Create.run(['config/percy.config.js']);
let filename = path.join('.config', 'percy.config.js');
await Create.run([filename]);
expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual(['[percy] Created Percy config: config/percy.config.js\n']);
expect(getMockConfig('config/percy.config.js')).toBe(PercyConfig.stringify('js'));
expect(logger.stdout).toEqual([`[percy] Created Percy config: ${filename}\n`]);
expect(getMockConfig(filename)).toBe(PercyConfig.stringify('js'));
});

it('logs an error and exits when the filetype is unsupported', async () => {
await expect(Create.run(['config/percy.config.php'])).rejects.toThrow('EEXIT: 1');
await expect(Create.run([path.join('.config', 'percy.config.php')]))
.rejects.toThrow('EEXIT: 1');
expect(logger.stdout).toEqual([]);
expect(logger.stderr).toEqual(['[percy] Unsupported filetype: php\n']);
});
Expand Down
9 changes: 6 additions & 3 deletions packages/cli-config/test/migrate.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import path from 'path';
import expect from 'expect';
import PercyConfig from '@percy/config';
import { logger, mockConfig, getMockConfig } from './helpers';
Expand Down Expand Up @@ -76,7 +77,7 @@ describe('percy config:migrate', () => {
});

it('errors and exits when a config cannot be found', async () => {
await expect(Migrate.run(['.config/percy.yml']))
await expect(Migrate.run([path.join('.config', 'percy.yml')]))
.rejects.toThrow('EEXIT: 1');

expect(logger.stdout).toEqual([]);
Expand All @@ -86,11 +87,13 @@ describe('percy config:migrate', () => {
});

it('errors and exits when a config cannot be parsed', async () => {
mockConfig('.config/percy.yml', () => {
let filename = path.join('.config', 'percy.yml');

mockConfig(filename, () => {
throw new Error('test');
});

await expect(Migrate.run(['.config/percy.yml']))
await expect(Migrate.run([filename]))
.rejects.toThrow('EEXIT: 1');

expect(logger.stdout).toEqual([]);
Expand Down
8 changes: 5 additions & 3 deletions packages/cli-config/test/validate.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import path from 'path';
import expect from 'expect';
import { logger, mockConfig } from './helpers';
import { Validate } from '../src/commands/config/validate';
Expand Down Expand Up @@ -43,12 +44,13 @@ describe('percy config:validate', () => {
});

it('logs debug info for a provided valid config file', async () => {
mockConfig('config/percy.yml', 'version: 2\ntest:\n value: config');
await Validate.run(['config/percy.yml']);
let filename = path.join('.config', 'percy.yml');
mockConfig(filename, 'version: 2\ntest:\n value: config');
await Validate.run([filename]);

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([
'[percy] Found config file: config/percy.yml\n',
`[percy] Found config file: ${filename}\n`,
'[percy] Using config:\n' + [
'{',
' version: 2,',
Expand Down
18 changes: 9 additions & 9 deletions packages/cli-exec/test/exec.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ describe('percy exec', () => {
});

it('starts and stops the percy process around the command', async () => {
await Exec.run(['--', 'sleep', '0.1']);
await Exec.run(['--', 'node', '--eval', '']);

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([
'[percy] Percy has started!\n',
'[percy] Created build #1: https://percy.io/test/test/123\n',
'[percy] Running "sleep 0.1"\n',
'[percy] Running "node --eval "\n',
'[percy] Stopping percy...\n',
'[percy] Finalized build #1: https://percy.io/test/test/123\n',
'[percy] Done!\n'
Expand All @@ -47,13 +47,13 @@ describe('percy exec', () => {

it('sets the parallel total when the --parallel flag is provided', async () => {
expect(process.env.PERCY_PARALLEL_TOTAL).toBeUndefined();
await Exec.run(['--parallel', '--', 'sleep', '0.1']);
await Exec.run(['--parallel', '--', 'node', '--eval', '']);

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([
'[percy] Percy has started!\n',
'[percy] Created build #1: https://percy.io/test/test/123\n',
'[percy] Running "sleep 0.1"\n',
'[percy] Running "node --eval "\n',
'[percy] Stopping percy...\n',
'[percy] Finalized build #1: https://percy.io/test/test/123\n',
'[percy] Done!\n'
Expand All @@ -64,32 +64,32 @@ describe('percy exec', () => {

it('runs the command even when percy is disabled', async () => {
process.env.PERCY_ENABLE = '0';
await Exec.run(['--', 'sleep', '0.1']);
await Exec.run(['--', 'node', '--eval', '']);

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([]);
});

it('runs the command even when PERCY_TOKEN is missing', async () => {
delete process.env.PERCY_TOKEN;
await Exec.run(['--', 'sleep', '0.1']);
await Exec.run(['--', 'node', '--eval', '']);

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([
'[percy] Skipping visual tests - Missing Percy token\n',
'[percy] Running "sleep 0.1"\n'
'[percy] Running "node --eval "\n'
]);
});

it('forwards the command status', async () => {
await expect(Exec.run(['--', 'bash', '-c', 'exit 3']))
await expect(Exec.run(['--', 'node', '--eval', 'process.exit(3)']))
.rejects.toThrow('EEXIT: 3');

expect(logger.stderr).toEqual([]);
expect(logger.stdout).toEqual([
'[percy] Percy has started!\n',
'[percy] Created build #1: https://percy.io/test/test/123\n',
'[percy] Running "bash -c exit 3"\n',
'[percy] Running "node --eval process.exit(3)"\n',
'[percy] Stopping percy...\n',
'[percy] Finalized build #1: https://percy.io/test/test/123\n',
'[percy] Done!\n'
Expand Down
8 changes: 5 additions & 3 deletions packages/config/test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import path from 'path';
import expect from 'expect';
import logger from '@percy/logger/test/helper';
import mockConfig from './helper';
Expand Down Expand Up @@ -225,23 +226,24 @@ describe('PercyConfig', () => {
});

it('can search a provided directory for a config file', () => {
let filename = path.join('config', '.percy.yml');
logger.loglevel('debug');

mockConfig('config/.percy.yml', [
mockConfig(filename, [
'version: 2',
'test:',
' value: config/percy'
].join('\n'));

expect(PercyConfig.load({ path: 'config/' }))
expect(PercyConfig.load({ path: 'config' }))
.toEqual({
version: 2,
test: { value: 'config/percy' }
});

expect(logger.stdout).toEqual([]);
expect(logger.stderr).toContain(
'[percy:config] Found config file: config/.percy.yml\n'
`[percy:config] Found config file: ${filename}\n`
);
});

Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/discovery/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ export default class Browser extends EventEmitter {

// after closing, attempt to clean up the profile directory
await closed.then(() => new Promise(resolve => {
// needed due to a bug in Node 12 - https://github.com/nodejs/node/issues/27097
this.process?.stdin.end();
this.process?.stdout.end();
this.process?.stderr.end();

/* istanbul ignore else: sanity */
if (this.profile) {
rimraf(this.profile, error => {
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/utils/install-browser.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* istanbul ignore file: this utility is required to work before tests to download the browser
* binary; since it is technically tested before the tests run, it does not generate coverage */
import path from 'path';
import https from 'https';
import {
Expand All @@ -10,7 +12,6 @@ import logger from '@percy/logger';
import readableBytes from './bytes';

// used to determine platform defaults
/* istanbul ignore next: hard to cover sans combined reports */
const platform = (
process.platform === 'win32' && process.arch === 'x64'
? 'win64' : process.platform
Expand Down Expand Up @@ -63,7 +64,6 @@ export default async function install({
// download the file at the given URL and log progress
await new Promise((resolve, reject) => {
https.get(url, response => {
/* istanbul ignore next: failsafe */
if (response.statusCode !== 200) {
response.resume();
reject(new Error(`Download failed: ${response.statusCode} - ${url}`));
Expand Down Expand Up @@ -96,7 +96,6 @@ export default async function install({
logger().info(`Successfully downloaded ${browser}`);
} finally {
// always cleanup
/* istanbul ignore next: hard to cover download failure */
if (existsSync(dlpath)) {
await new Promise(resolve => rimraf(dlpath, resolve));
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ afterEach(function(done) {
}

// cleanup tmp files
rimraf(path.join(os.tmpdir(), 'percy'), done);
rimraf(path.join(os.tmpdir(), 'percy'), () => done());
});

export { logger, mockAPI };
Expand Down
21 changes: 0 additions & 21 deletions packages/core/test/percy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,27 +172,6 @@ describe('Percy', () => {
await expect(Percy.start({ token: 'PERCY_TOKEN' })).rejects
.toThrow('Percy is already running or the port is in use');
});

it('maybe downloads the browser for asset discovery', async function() {
let local = require('path').join(__dirname, '../.local-chromium');
let { existsSync } = require('fs');

this.retries(5); // this flakes on windows due to its non-atomic fs functions
require('rimraf').sync(local);
expect(existsSync(local)).toBe(false);
this.retries(0);

// the install script will always log
percy.loglevel('silent');

this.timeout(0); // this might take a minute to download
await percy.start();
expect(existsSync(local)).toBe(true);

expect(logger.stderr).toEqual([]);
expect(logger.stdout[0]).toEqual('[percy] Chromium not found, downloading...\n');
expect(logger.stdout[logger.stdout.length - 1]).toEqual('[percy] Successfully downloaded Chromium\n');
});
});

describe('#stop()', () => {
Expand Down
11 changes: 4 additions & 7 deletions packages/dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,16 @@
"babel": {
"extends": "../../babel.config.js",
"presets": [
[
"@babel/env",
{
"targets": "last 2 version"
}
]
["@babel/env", {
"targets": "last 2 version"
}]
]
},
"devDependencies": {
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.1.0",
"interactor.js": "^2.0.0-beta.8",
"interactor.js": "^2.0.0-beta.10",
"karma": "^6.0.2",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.0.3",
Expand Down
6 changes: 3 additions & 3 deletions scripts/babel-register.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ require('@babel/register')({
rootMode: 'upward',
babelrcRoots: ['.'],

// specified without the cwd so tests can share helpers
only: [
// specified without the cwd so tests can share helpers
new RegExp(
['packages', '.*?', '(src|test)']
// escape windows path seperators and escape the escape
['(@percy|packages)', '.+?', '(src|test)']
// escape windows path separators and escape the escape
.join(path.sep === '/' ? '/' : '\\\\')
)
]
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5161,7 +5161,7 @@ inquirer@^6.2.0:
strip-ansi "^5.1.0"
through "^2.3.6"

interactor.js@^2.0.0-beta.8:
interactor.js@^2.0.0-beta.10:
version "2.0.0-beta.10"
resolved "https://registry.yarnpkg.com/interactor.js/-/interactor.js-2.0.0-beta.10.tgz#f009c769d535bfe78794caf3d85b6c46675b9b18"
integrity sha512-PI6bW6spipafmdT0BdodS90wDIeFSK4OL/0WK79Vb3z7a0GYsQyZSgIIH11zWqofe0CNpxIrdj6pbG/EpQ8+Tw==
Expand Down

0 comments on commit d168ffb

Please sign in to comment.