Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/client/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,25 @@ describe('PercyClient', () => {
})).toBeRejectedWithError('sha, filepath or content should be present in tiles object');
});
});

describe('when labels are provided on a POA comparison', () => {
beforeEach(async () => {
await client.sendComparison(123, {
name: 'test snapshot name',
tag: { name: 'test tag' },
tiles: [{ content: base64encode('tile') }],
labels: 'qa, smoke,release'
});
});

it('forwards labels as tags onto the snapshot', () => {
expect(api.requests['/builds/123/snapshots'][0].body.data.attributes.tags).toEqual([
{ id: null, name: 'qa' },
{ id: null, name: 'smoke' },
{ id: null, name: 'release' }
]);
});
});
});

describe('#tokenType', () => {
Expand Down
55 changes: 55 additions & 0 deletions packages/core/test/api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,61 @@ describe('API Server', () => {
expect(percy.upload).toHaveBeenCalledOnceWith({ sync: true }, jasmine.objectContaining({}), 'automate');
});

it('has a /automateScreenshot endpoint that propagates labels through to #upload()', async () => {
let resolve, test = new Promise(r => (resolve = r));
spyOn(percy, 'upload').and.returnValue(test);
// Simulate what the real WebdriverUtils.captureScreenshot does:
// it must copy options.labels onto the returned comparisonData.
let captureScreenshotSpy = spyOn(WebdriverUtils, 'captureScreenshot').and.callFake(({ options }) => {
return Promise.resolve({
name: 'Snapshot name',
tag: { name: 'tag-1' },
tiles: [],
metadata: {},
sync: options.sync,
testCase: options.testCase,
labels: options.labels,
thTestCaseExecutionId: options.thTestCaseExecutionId
});
});

await percy.start();

await expectAsync(request('/percy/automateScreenshot', {
body: {
name: 'Snapshot name',
client_info: 'client',
environment_info: 'environment',
options: {
labels: 'qa,smoke',
testCase: 'tc-1',
thTestCaseExecutionId: 'exec-99'
}
},
method: 'post'
})).toBeResolvedTo({ success: true });

expect(captureScreenshotSpy).toHaveBeenCalledOnceWith(jasmine.objectContaining({
options: jasmine.objectContaining({
labels: 'qa,smoke',
testCase: 'tc-1',
thTestCaseExecutionId: 'exec-99'
})
}));

expect(percy.upload).toHaveBeenCalledOnceWith(
jasmine.objectContaining({
labels: 'qa,smoke',
testCase: 'tc-1',
thTestCaseExecutionId: 'exec-99'
}),
null,
'automate'
);

resolve();
});

// Cross-consumer drain canary for /percy/automateScreenshot. Mirrors the
// maestro-screenshot and /comparison canaries elsewhere in this file. See
// docs/solutions/best-practices/2026-05-20-maestro-sync-promise-bug-investigation.md.
Expand Down
1 change: 1 addition & 0 deletions packages/webdriver-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default class WebdriverUtils {
comparisonData.metadata.cliScreenshotEndTime = Date.now();
comparisonData.sync = options.sync;
comparisonData.testCase = options.testCase;
comparisonData.labels = options.labels;
comparisonData.thTestCaseExecutionId = options.thTestCaseExecutionId;
log.debug(`[${snapshotName}] : Comparison Data: ${JSON.stringify(comparisonData)}`);
return comparisonData;
Expand Down
104 changes: 104 additions & 0 deletions packages/webdriver-utils/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import WebdriverUtils from '../src/index.js';
import ProviderResolver from '../src/providers/providerResolver.js';
import PlaywrightProvider from '../src/providers/playwrightProvider.js';

describe('WebdriverUtils.captureScreenshot', () => {
let providerStub;
let baseArgs;
let providerResponse;

beforeEach(() => {
providerResponse = {
name: 'snap',
tag: { name: 'tag-1' },
tiles: [],
metadata: {}
};

providerStub = {
createDriver: jasmine.createSpy('createDriver').and.resolveTo(),
screenshot: jasmine.createSpy('screenshot').and.callFake(() => Promise.resolve({ ...providerResponse }))
};

spyOn(ProviderResolver, 'resolve').and.returnValue(providerStub);

baseArgs = {
sessionId: '1234',
commandExecutorUrl: 'https://localhost/command-executor',
capabilities: {},
sessionCapabilities: {},
framework: null,
snapshotName: 'snap',
clientInfo: 'client',
environmentInfo: 'env',
options: {},
buildInfo: { id: '123' }
};
});

it('forwards labels from options onto comparisonData for POA snapshots', async () => {
baseArgs.options = {
sync: false,
testCase: 'tc',
labels: 'label1,label2',
thTestCaseExecutionId: 'exec-1'
};

const result = await WebdriverUtils.captureScreenshot(baseArgs);

expect(result.labels).toEqual('label1,label2');
expect(result.testCase).toEqual('tc');
expect(result.thTestCaseExecutionId).toEqual('exec-1');
expect(result.sync).toEqual(false);
});

it('sets labels to undefined when not provided in options', async () => {
baseArgs.options = { testCase: 'tc' };

const result = await WebdriverUtils.captureScreenshot(baseArgs);

expect(result.labels).toBeUndefined();
expect(result.testCase).toEqual('tc');
});

it('does not lose labels even when provider response has none', async () => {
baseArgs.options = { labels: 'only-label' };

const result = await WebdriverUtils.captureScreenshot(baseArgs);

expect(result.labels).toEqual('only-label');
});

it('forwards labels through the playwright provider too', async () => {
spyOn(PlaywrightProvider.prototype, 'createDriver').and.resolveTo();
spyOn(PlaywrightProvider.prototype, 'screenshot').and.resolveTo({
name: 'snap', tag: { name: 'pw' }, tiles: [], metadata: {}
});

baseArgs.framework = 'playwright';
baseArgs.options = { labels: 'pw-label' };

const result = await WebdriverUtils.captureScreenshot(baseArgs);

expect(result.labels).toEqual('pw-label');
});

it('re-throws errors from the provider without setting labels', async () => {
providerStub.screenshot.and.rejectWith(new Error('boom'));
baseArgs.options = { labels: 'x' };

await expectAsync(WebdriverUtils.captureScreenshot(baseArgs))
.toBeRejectedWithError('boom');
});

it('falls back to default options and buildInfo when caller omits them', async () => {
const { options, buildInfo, ...argsWithoutDefaults } = baseArgs;

const result = await WebdriverUtils.captureScreenshot(argsWithoutDefaults);

expect(result.labels).toBeUndefined();
expect(result.testCase).toBeUndefined();
expect(result.thTestCaseExecutionId).toBeUndefined();
expect(providerStub.screenshot).toHaveBeenCalledWith('snap', {});
});
});
96 changes: 0 additions & 96 deletions test/regression/pages/comprehensive.html

This file was deleted.

Loading