Skip to content

Commit d8efcb6

Browse files
authored
feat: support URL sources upload to portal (#1235)
1 parent 7b6e72c commit d8efcb6

File tree

13 files changed

+362
-45
lines changed

13 files changed

+362
-45
lines changed

e2e/plugin-axe-e2e/tests/__snapshots__/collect.e2e.test.ts.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ exports[`PLUGIN collect report with axe-plugin NPM package > should run plugin o
497497
"details": {
498498
"issues": [
499499
{
500-
"message": "[\`body > button\`] Fix any of the following: Element does not have inner text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute Element does not have an implicit (wrapped) <label> Element does not have an explicit <label> Element's default semantics were not overridden with role="none" or role="presentation"",
500+
"message": "Element does not have inner text that is visible to screen readers",
501501
"severity": "error",
502502
"source": {
503503
"selector": "body > button",
@@ -528,7 +528,7 @@ exports[`PLUGIN collect report with axe-plugin NPM package > should run plugin o
528528
"details": {
529529
"issues": [
530530
{
531-
"message": "[\`.low-contrast\`] Fix any of the following: Element has insufficient color contrast of 1.57 (foreground color: #777777, background color: #999999, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1",
531+
"message": "Element has insufficient color contrast of 1.57 (foreground color: #777777, background color: #999999, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1",
532532
"severity": "error",
533533
"source": {
534534
"selector": ".low-contrast",
@@ -624,7 +624,7 @@ exports[`PLUGIN collect report with axe-plugin NPM package > should run plugin o
624624
"details": {
625625
"issues": [
626626
{
627-
"message": "[\`div[role="button"]\`] Fix any of the following: Invalid ARIA attribute name: aria-invalid-attribute",
627+
"message": "Invalid ARIA attribute name: aria-invalid-attribute",
628628
"severity": "error",
629629
"source": {
630630
"selector": "div[role=\"button\"]",
@@ -648,7 +648,7 @@ exports[`PLUGIN collect report with axe-plugin NPM package > should run plugin o
648648
"details": {
649649
"issues": [
650650
{
651-
"message": "[\`img\`] Fix any of the following: Element does not have an alt attribute aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute Element's default semantics were not overridden with role="none" or role="presentation"",
651+
"message": "Element does not have an alt attribute",
652652
"severity": "error",
653653
"source": {
654654
"selector": "img",
@@ -670,7 +670,7 @@ exports[`PLUGIN collect report with axe-plugin NPM package > should run plugin o
670670
"details": {
671671
"issues": [
672672
{
673-
"message": "[\`a\`] Fix all of the following: Element is in tab order and does not have accessible text Fix any of the following: Element does not have text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute",
673+
"message": "Element is in tab order and does not have accessible text",
674674
"severity": "error",
675675
"source": {
676676
"selector": "a",

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"private": true,
2121
"dependencies": {
2222
"@axe-core/playwright": "^4.11.0",
23-
"@code-pushup/portal-client": "^0.16.0",
23+
"@code-pushup/portal-client": "^0.17.0",
2424
"@nx/devkit": "22.3.3",
2525
"@swc/helpers": "0.5.18",
2626
"ansis": "^3.3.2",

packages/ci/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"type": "module",
2828
"dependencies": {
2929
"@code-pushup/models": "0.112.0",
30-
"@code-pushup/portal-client": "^0.16.0",
30+
"@code-pushup/portal-client": "^0.17.0",
3131
"@code-pushup/utils": "0.112.0",
3232
"ansis": "^3.3.2",
3333
"glob": "^11.0.1",

packages/ci/src/lib/portal/__snapshots__/transform.unit.test.ts.snap

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,36 @@ exports[`transformGQLReport > should convert full GraphQL report to valid report
197197
"slug": "bundle-stats",
198198
"title": "Bundle stats",
199199
},
200+
{
201+
"audits": [
202+
{
203+
"details": {
204+
"issues": [
205+
{
206+
"message": "Element has insufficient color contrast of 4.33",
207+
"severity": "error",
208+
"source": {
209+
"selector": ".hero > span:nth-child(2)",
210+
"snippet": "<span style="color: #aaa">Low contrast</span>",
211+
"url": "https://example.com/",
212+
},
213+
},
214+
],
215+
},
216+
"displayValue": "1 error",
217+
"score": 0,
218+
"slug": "color-contrast",
219+
"title": "Elements must meet minimum color contrast ratio thresholds",
220+
"value": 1,
221+
},
222+
],
223+
"date": "2025-08-01T00:10:25.000Z",
224+
"duration": 5000,
225+
"groups": [],
226+
"icon": "folder-syntax",
227+
"slug": "axe",
228+
"title": "Axe accessibility",
229+
},
200230
],
201231
"version": "0.42.0",
202232
}

packages/ci/src/lib/portal/transform.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ function transformGQLIssue(issue: IssueFragment): Issue {
166166
}),
167167
},
168168
}),
169+
...(issue.source?.__typename === 'SourceUrlLocation' && {
170+
source: {
171+
url: issue.source.url,
172+
...(issue.source.snippet != null && {
173+
snippet: issue.source.snippet,
174+
}),
175+
...(issue.source.selector != null && {
176+
selector: issue.source.selector,
177+
}),
178+
},
179+
}),
169180
};
170181
}
171182

packages/ci/src/lib/portal/transform.unit.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,29 @@ describe('transformGQLReport', () => {
207207
},
208208
groups: [],
209209
},
210+
{
211+
slug: 'axe',
212+
title: 'Axe accessibility',
213+
icon: 'folder-syntax',
214+
runnerStartDate: '2025-08-01T00:10:25.000Z',
215+
runnerDuration: 5000,
216+
audits: {
217+
edges: [
218+
{
219+
node: {
220+
slug: 'color-contrast',
221+
title:
222+
'Elements must meet minimum color contrast ratio thresholds',
223+
score: 0,
224+
value: 1,
225+
formattedValue: '1 error',
226+
details: { enabled: true, trees: [], tables: [] },
227+
},
228+
},
229+
],
230+
},
231+
groups: [],
232+
},
210233
],
211234
issues: {
212235
edges: [
@@ -231,6 +254,19 @@ describe('transformGQLReport', () => {
231254
severity: IssueSeverity.Warning,
232255
},
233256
},
257+
{
258+
node: {
259+
audit: { plugin: { slug: 'axe' }, slug: 'color-contrast' },
260+
message: 'Element has insufficient color contrast of 4.33',
261+
severity: IssueSeverity.Error,
262+
source: {
263+
__typename: 'SourceUrlLocation',
264+
url: 'https://example.com/',
265+
snippet: '<span style="color: #aaa">Low contrast</span>',
266+
selector: '.hero > span:nth-child(2)',
267+
},
268+
},
269+
},
234270
],
235271
},
236272
};

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"ansis": "^3.3.0"
4545
},
4646
"peerDependencies": {
47-
"@code-pushup/portal-client": "^0.16.0"
47+
"@code-pushup/portal-client": "^0.17.0"
4848
},
4949
"peerDependenciesMeta": {
5050
"@code-pushup/portal-client": {

packages/core/src/lib/implementation/report-to-gql.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import type {
3333
TableAlignment,
3434
Tree,
3535
} from '@code-pushup/models';
36-
import { isFileIssue } from '@code-pushup/utils';
36+
import { isFileIssue, isUrlIssue } from '@code-pushup/utils';
3737

3838
export function reportToGQL(
3939
report: Report,
@@ -115,6 +115,12 @@ export function issueToGQL(issue: Issue): PortalIssue {
115115
sourceEndLine: issue.source.position?.endLine,
116116
sourceEndColumn: issue.source.position?.endColumn,
117117
}),
118+
...(isUrlIssue(issue) && {
119+
sourceType: safeEnum<PortalIssueSourceType>('Url'),
120+
sourceUrl: issue.source.url,
121+
sourceSnippet: issue.source.snippet,
122+
sourceSelector: issue.source.selector,
123+
}),
118124
};
119125
}
120126

packages/core/src/lib/implementation/report-to-gql.unit.test.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type AuditReportTree, TreeType } from '@code-pushup/portal-client';
22
import { issueToGQL, tableToGQL, treeToGQL } from './report-to-gql.js';
33

44
describe('issueToGQL', () => {
5-
it('transforms issue to GraphQL input type', () => {
5+
it('should transform issue with file source to GraphQL input type', () => {
66
expect(
77
issueToGQL({
88
message: 'No let, use const instead.',
@@ -23,6 +23,27 @@ describe('issueToGQL', () => {
2323
sourceEndColumn: 25,
2424
});
2525
});
26+
27+
it('should transform issue with URL source to GraphQL input type', () => {
28+
expect(
29+
issueToGQL({
30+
message: 'Fix any of the following: Unable to determine contrast ratio',
31+
severity: 'error',
32+
source: {
33+
url: 'https://code-pushup.dev/',
34+
snippet: '<span>measure development KPIs</span>',
35+
selector: '.text-box > span:nth-child(3)',
36+
},
37+
}),
38+
).toStrictEqual({
39+
message: 'Fix any of the following: Unable to determine contrast ratio',
40+
severity: 'Error',
41+
sourceSelector: '.text-box > span:nth-child(3)',
42+
sourceSnippet: '<span>measure development KPIs</span>',
43+
sourceType: 'Url',
44+
sourceUrl: 'https://code-pushup.dev/',
45+
});
46+
});
2647
});
2748

2849
describe('tableToGQL', () => {

0 commit comments

Comments
 (0)