Skip to content
This repository has been archived by the owner on Mar 31, 2021. It is now read-only.

Commit

Permalink
Debug Mode + Bug Fixes (#78)
Browse files Browse the repository at this point in the history
* Add debug mode that outputs percy files to disk instead of uploading them.

* Don't allow async suites.

* Fix tests on Windows.

* Ensure context is always set to the percy root directory.

* Try to format error in debug.

* Add a few clarify notes when running debug mode.
  • Loading branch information
thomashuston authored Sep 12, 2017
1 parent 8ea1dc5 commit fc9fd8e
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 82 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ packages/*/lib

# Packed npm
*.tgz

# Percy debug files
.percy-debug
2 changes: 1 addition & 1 deletion packages/react-percy-api-client/src/build/createBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function createBuild(percyClient, resources) {
resolve(response.body.data);
},
err => {
debug('error creating build: %s (%s)', err.error, err.statusCode);
debug('error creating build: %o (%s)', err.error, err.statusCode);
reject(err);
},
);
Expand Down
24 changes: 24 additions & 0 deletions packages/react-percy-ci/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ import createDebug from 'debug';
import { EntryNames } from '@percy-io/react-percy-webpack';
import Environment from './Environment';
import findEntryPath from './findEntryPath';
import fs from 'fs';
import getHTML from './getHTML';
import getQueryParamsForSnapshot from './getQueryParamsForSnapshot';
import path from 'path';
import reporter from './reporter';

const debug = createDebug('react-percy:ci');

export default async function run(percyConfig, webpackConfig, percyToken) {
const client = new ApiClient(percyToken);

if (percyConfig.debug) {
reporter.log(chalk.blue.bold('DEBUG MODE: No snapshots will be uploaded to Percy'));
}

reporter.log('Compiling...');
debug('compiling assets');
const assets = await compileAssets(percyConfig, webpackConfig);
Expand All @@ -31,6 +37,24 @@ export default async function run(percyConfig, webpackConfig, percyToken) {
return;
}

if (percyConfig.debug) {
const html = getHTML(assets);
const htmlPath = path.join(percyConfig.rootDir, '.percy-debug', 'index.html');
fs.writeFileSync(htmlPath, html);
reporter.log(
'Debug snapshots by opening %s in your browser and appending the following query strings:',
chalk.blue.underline(`file://${htmlPath}`),
);
snapshots.sort().forEach(snapshot => {
reporter.log(
` %s ${chalk.green('?snapshot=%s')}`,
snapshot.name,
encodeURIComponent(snapshot.name),
);
});
return;
}

reporter.log(
'Uploading %d snapshot%s to Percy',
snapshots.length,
Expand Down
20 changes: 20 additions & 0 deletions packages/react-percy-config/src/__tests__/normalize-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ import defaults from '../defaults';
import normalize from '../normalize';
import path from 'path';

it('sets `debug` to false given `debug` mode is off', () => {
const config = {};
const packageRoot = '/package/root';
const debug = false;

const normalizedConfig = normalize(config, packageRoot, debug);

expect(normalizedConfig.debug).toBe(false);
});

it('sets `debug` to true given `debug` mode is on', () => {
const config = {};
const packageRoot = '/package/root';
const debug = true;

const normalizedConfig = normalize(config, packageRoot, debug);

expect(normalizedConfig.debug).toBe(true);
});

it('sets `includeFiles` to an empty array given no `includeFiles` in config', () => {
const config = {};
const packageRoot = '/package/root';
Expand Down
4 changes: 2 additions & 2 deletions packages/react-percy-config/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import loadFromPackage from './loadFromPackage';
import normalize from './normalize';
import path from 'path';

export default function readPercyConfig(packageRoot) {
export default function readPercyConfig(packageRoot, debug) {
const packageJsonPath = path.join(packageRoot, 'package.json');
const config = loadFromPackage(packageJsonPath);
return normalize(config, packageRoot);
return normalize(config, packageRoot, debug);
}
4 changes: 3 additions & 1 deletion packages/react-percy-config/src/normalize.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import defaults from './defaults';
import path from 'path';

export default function normalize(config, packageRoot) {
export default function normalize(config, packageRoot, debug = false) {
const normalizedConfig = {};

normalizedConfig.debug = debug;

normalizedConfig.includeFiles = config.includeFiles || [];

normalizedConfig.renderer = config.renderer || defaults.renderer;
Expand Down
1 change: 1 addition & 0 deletions packages/react-percy-test-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
],
"dependencies": {
"babel-runtime": "^6.26.0",
"debug": "^2.6.3",
"promise-each": "^2.2.0"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`snapshot throws if a snapshot with the same name has already been added to a different suite with the same name 1`] = `[Error: A snapshot named \`Suite: snapshot\` has already been added, please use a different name]`;
exports[`snapshot throws if a snapshot with the same name has already been added to a different suite with the same name 1`] = `"A snapshot named \`Suite: snapshot\` has already been added, please use a different name"`;
Original file line number Diff line number Diff line change
Expand Up @@ -59,86 +59,46 @@ describe('afterAll', () => {
});

describe('suite', () => {
it('adds the suite as a child of the current suite given no callback', async () => {
await common.suite('suite');
it('adds the suite as a child of the current suite given no callback', () => {
common.suite('suite');

expect(suites[0].addSuite).toHaveBeenCalledWith(expect.any(Suite));
});

it('adds the suite as a child of the current suite given synchronous callback', async () => {
await common.suite('suite', jest.fn());
it('adds the suite as a child of the current suite given callback', () => {
common.suite('suite', jest.fn());

expect(suites[0].addSuite).toHaveBeenCalledWith(expect.any(Suite));
});

it('adds the suite as a child of the current suite given asynchronous callback', async () => {
const fn = () => new Promise(resolve => setTimeout(resolve, 1));
await common.suite('suite', fn);

expect(suites[0].addSuite).toHaveBeenCalledWith(expect.any(Suite));
});

it('returns the new suite given no callback', async () => {
const newSuite = await common.suite('suite');
it('returns the new suite given no callback', () => {
const newSuite = common.suite('suite');

expect(newSuite).toEqual(expect.any(Suite));
});

it('returns the new suite given synchronous callback', async () => {
const newSuite = await common.suite('suite', jest.fn());
it('returns the new suite given callback', () => {
const newSuite = common.suite('suite', jest.fn());

expect(newSuite).toEqual(expect.any(Suite));
});

it('returns the new suite given asynchronous callback', async () => {
const fn = () => new Promise(resolve => setTimeout(resolve, 1));
const newSuite = await common.suite('suite', fn);

expect(newSuite).toEqual(expect.any(Suite));
});

it('sets the new suite as the current suite while executing synchronous callback', async () => {
it('sets the new suite as the current suite while executing callback', () => {
let callbackCurrentSuite;
const callback = jest.fn(() => {
callbackCurrentSuite = suites[0];
});

const newSuite = await common.suite('suite', callback);

expect(callbackCurrentSuite).toBe(newSuite);
expect(callbackCurrentSuite).not.toBe(suites[0]);
});

it('sets the new suite as the current suite while executing asynchronous callback', async () => {
let callbackCurrentSuite;
const callback = () =>
new Promise(resolve => {
setTimeout(() => {
callbackCurrentSuite = suites[0];
resolve();
}, 5);
});

const newSuite = await common.suite('suite', callback);
const newSuite = common.suite('suite', callback);

expect(callbackCurrentSuite).toBe(newSuite);
expect(callbackCurrentSuite).not.toBe(suites[0]);
});

it('restores the current suite after executing synchronous callback', async () => {
it('restores the current suite after executing callback', () => {
const currentSuite = suites[0];

const newSuite = await common.suite('suite', jest.fn());

expect(suites[0]).toBe(currentSuite);
expect(suites[0]).not.toBe(newSuite);
});

it('restores the current suite after executing asynchronous callback', async () => {
const currentSuite = suites[0];
const fn = () => new Promise(resolve => setTimeout(resolve, 1));

const newSuite = await common.suite('suite', fn);
const newSuite = common.suite('suite', jest.fn());

expect(suites[0]).toBe(currentSuite);
expect(suites[0]).not.toBe(newSuite);
Expand All @@ -158,31 +118,28 @@ describe('snapshot', () => {
expect(() => common.snapshot('snapshot 2', jest.fn())).not.toThrow();
});

it('throws if a snapshot with the same name has already been added to a different suite with the same name', async () => {
await common.suite('Suite', () => {
it('throws if a snapshot with the same name has already been added to a different suite with the same name', () => {
common.suite('Suite', () => {
common.snapshot('snapshot', jest.fn());
});

try {
await common.suite('Suite', () => {
expect(() =>
common.suite('Suite', () => {
common.snapshot('snapshot', jest.fn());
});
} catch (e) {
expect(e).toMatchSnapshot();
return;
}

throw new Error('adding second snapshot should have thrown');
}),
).toThrowErrorMatchingSnapshot();
});

it('does not throw if a snapshot with the same name has already been added to a different suite with a different name', async () => {
await common.suite('Suite 1', () => {
it('does not throw if a snapshot with the same name has already been added to a different suite with a different name', () => {
common.suite('Suite 1', () => {
common.snapshot('snapshot', jest.fn());
});

await common.suite('Suite 2', () => {
common.snapshot('snapshot', jest.fn());
});
expect(() =>
common.suite('Suite 2', () => {
common.snapshot('snapshot', jest.fn());
}),
).not.toThrow();
});

it('adds snapshot to the current suite', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import createDebug from 'debug';
import Snapshot from '../Snapshot';
import Suite from '../Suite';

const debug = createDebug('react-percy:test-framework');

export default function getCommonInterface(suites) {
const snapshotNames = {};

Expand All @@ -17,16 +20,22 @@ export default function getCommonInterface(suites) {
afterAll(fn) {
suites[0].addAfterAll(fn);
},
async suite(title, options, fn) {
suite(title, options, fn) {
if (typeof fn === 'undefined') {
fn = options;
options = undefined;
}
const suite = new Suite(title, options);
suites[0].addSuite(suite);
suites.unshift(suite);
if (suite.fullTitle()) {
debug('processing suite %o', suite.fullTitle());
}
if (typeof fn === 'function') {
await fn.call(suite);
fn.call(suite);
}
if (suite.fullTitle()) {
debug('finished processing suite %o', suite.fullTitle());
}
suites.shift();
return suite;
Expand All @@ -41,6 +50,7 @@ export default function getCommonInterface(suites) {
);
}
snapshotNames[snapshotFullTitle] = true;
debug('added snapshot %o', snapshotFullTitle);
return snapshot;
},
};
Expand Down
Loading

0 comments on commit fc9fd8e

Please sign in to comment.