Skip to content

Commit

Permalink
✨ Add ability to set percy config after core initialization (#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wil Wilsman committed Oct 11, 2021
1 parent cae1513 commit 56e4ea3
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
27 changes: 27 additions & 0 deletions packages/core/src/percy.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PercyClient from '@percy/client';
import PercyConfig from '@percy/config';
import { merge } from '@percy/config/dist/utils';
import logger from '@percy/logger';
import Queue from './queue';
import Browser from './browser';
Expand Down Expand Up @@ -94,6 +95,32 @@ export default class Percy {
return `http://localhost:${this.port}`;
}

// Set client & environment info, and override loaded config options
setConfig({ clientInfo, environmentInfo, ...config }) {
this.client.addClientInfo(clientInfo);
this.client.addEnvironmentInfo(environmentInfo);

// normalize config and do nothing if empty
config = PercyConfig.normalize(config, { schema: '/config' });
if (!config) return this.config;

// validate provided config options
let errors = PercyConfig.validate(config);

if (errors) {
this.log.warn('Invalid config:');
for (let e of errors) this.log.warn(`- ${e.path}: ${e.message}`);
}

// merge and override existing config options
this.config = merge([this.config, config], (path, prev, next) => {
// replace arrays instead of merging
return Array.isArray(next) && [path, next];
});

return this.config;
}

// Resolves once snapshot and upload queues are idle
async idle() {
await this.#snapshots.idle();
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ export default function createPercyServer(percy) {
build: percy.build
}],

// remotely get and set percy config options
'/percy/config': ({ body }) => [200, 'application/json', {
config: body ? percy.setConfig(body) : percy.config,
success: true
}],

// responds when idle
'/percy/idle': () => percy.idle()
.then(() => [200, 'application/json', { success: true }]),
Expand Down
37 changes: 37 additions & 0 deletions packages/core/test/percy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,43 @@ describe('Percy', () => {
});
});

describe('#setConfig(config)', () => {
it('adds client and environment information', () => {
expect(percy.setConfig({
clientInfo: 'client/info',
environmentInfo: 'env/info'
})).toEqual(percy.config);

expect(percy.client.clientInfo).toContain('client/info');
expect(percy.client.environmentInfo).toContain('env/info');
});

it('merges existing and provided config options', () => {
expect(percy.setConfig({
snapshot: { widths: [1000] }
})).toEqual({
...percy.config,
snapshot: {
...percy.config.snapshot,
widths: [1000]
}
});
});

it('warns and ignores invalid config options', () => {
expect(percy.setConfig({
snapshot: { widths: 1000 },
foo: 'bar'
})).toEqual(percy.config);

expect(logger.stderr).toEqual([
'[percy] Invalid config:',
'[percy] - foo: unknown property',
'[percy] - snapshot.widths: must be an array, received a number'
]);
});
});

describe('#start()', () => {
it('creates a new build', async () => {
await expectAsync(percy.start()).toBeResolved();
Expand Down
34 changes: 34 additions & 0 deletions packages/core/test/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ describe('Server', () => {
});
});

it('has a /config endpoint that returns loaded config options', async () => {
await percy.start();

let response = await fetch('http://localhost:1337/percy/config');
await expectAsync(response.json()).toBeResolvedTo({
success: true,
config: PercyConfig.getDefaults()
});
});

it('can set config options via the /config endpoint', async () => {
await percy.start();

let response = await fetch('http://localhost:1337/percy/config', {
method: 'POST',
body: JSON.stringify({
snapshot: { widths: [1000] }
})
});

await expectAsync(response.json()).toBeResolvedTo({
success: true,
config: PercyConfig.getDefaults({
snapshot: { widths: [1000] }
})
});

expect(percy.config).toEqual(
PercyConfig.getDefaults({
snapshot: { widths: [1000] }
})
);
});

it('has an /idle endpoint that calls #idle()', async () => {
spyOn(percy, 'idle').and.resolveTo();
await percy.start();
Expand Down

0 comments on commit 56e4ea3

Please sign in to comment.