@freeappstore/compliance 0.3.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/checks/brand-fonts.d.ts +2 -1
  2. package/dist/checks/brand-fonts.d.ts.map +1 -1
  3. package/dist/checks/brand-fonts.js +11 -7
  4. package/dist/checks/brand-fonts.js.map +1 -1
  5. package/dist/checks/brand-tokens.d.ts +22 -0
  6. package/dist/checks/brand-tokens.d.ts.map +1 -0
  7. package/dist/checks/brand-tokens.js +53 -0
  8. package/dist/checks/brand-tokens.js.map +1 -0
  9. package/dist/checks/bundle-size.d.ts +7 -1
  10. package/dist/checks/bundle-size.d.ts.map +1 -1
  11. package/dist/checks/bundle-size.js +35 -15
  12. package/dist/checks/bundle-size.js.map +1 -1
  13. package/dist/checks/claude-md-slim.d.ts +4 -0
  14. package/dist/checks/claude-md-slim.d.ts.map +1 -0
  15. package/dist/checks/claude-md-slim.js +88 -0
  16. package/dist/checks/claude-md-slim.js.map +1 -0
  17. package/dist/checks/dark-mode.d.ts +20 -0
  18. package/dist/checks/dark-mode.d.ts.map +1 -0
  19. package/dist/checks/dark-mode.js +56 -0
  20. package/dist/checks/dark-mode.js.map +1 -0
  21. package/dist/checks/html-meta.d.ts +16 -0
  22. package/dist/checks/html-meta.d.ts.map +1 -0
  23. package/dist/checks/html-meta.js +51 -0
  24. package/dist/checks/html-meta.js.map +1 -0
  25. package/dist/checks/license-mit.d.ts +13 -0
  26. package/dist/checks/license-mit.d.ts.map +1 -0
  27. package/dist/checks/license-mit.js +45 -0
  28. package/dist/checks/license-mit.js.map +1 -0
  29. package/dist/checks/manifest.d.ts +2 -1
  30. package/dist/checks/manifest.d.ts.map +1 -1
  31. package/dist/checks/manifest.js +7 -12
  32. package/dist/checks/manifest.js.map +1 -1
  33. package/dist/checks/no-brand-overrides.d.ts +2 -1
  34. package/dist/checks/no-brand-overrides.d.ts.map +1 -1
  35. package/dist/checks/no-brand-overrides.js +94 -30
  36. package/dist/checks/no-brand-overrides.js.map +1 -1
  37. package/dist/checks/no-env-production.d.ts +16 -0
  38. package/dist/checks/no-env-production.d.ts.map +1 -0
  39. package/dist/checks/no-env-production.js +37 -0
  40. package/dist/checks/no-env-production.js.map +1 -0
  41. package/dist/checks/no-placeholders.d.ts +2 -1
  42. package/dist/checks/no-placeholders.d.ts.map +1 -1
  43. package/dist/checks/no-placeholders.js +11 -9
  44. package/dist/checks/no-placeholders.js.map +1 -1
  45. package/dist/checks/no-scroll.d.ts +2 -1
  46. package/dist/checks/no-scroll.d.ts.map +1 -1
  47. package/dist/checks/no-scroll.js +13 -47
  48. package/dist/checks/no-scroll.js.map +1 -1
  49. package/dist/checks/no-tracking.d.ts +2 -1
  50. package/dist/checks/no-tracking.d.ts.map +1 -1
  51. package/dist/checks/no-tracking.js +77 -21
  52. package/dist/checks/no-tracking.js.map +1 -1
  53. package/dist/checks/pwa-meta.d.ts +19 -0
  54. package/dist/checks/pwa-meta.d.ts.map +1 -0
  55. package/dist/checks/pwa-meta.js +42 -0
  56. package/dist/checks/pwa-meta.js.map +1 -0
  57. package/dist/checks/pwa-offline.d.ts +40 -0
  58. package/dist/checks/pwa-offline.d.ts.map +1 -0
  59. package/dist/checks/pwa-offline.js +388 -0
  60. package/dist/checks/pwa-offline.js.map +1 -0
  61. package/dist/checks/store-link.d.ts +17 -0
  62. package/dist/checks/store-link.d.ts.map +1 -0
  63. package/dist/checks/store-link.js +36 -0
  64. package/dist/checks/store-link.js.map +1 -0
  65. package/dist/checks/unsafe-vh.d.ts +2 -1
  66. package/dist/checks/unsafe-vh.d.ts.map +1 -1
  67. package/dist/checks/unsafe-vh.js +25 -15
  68. package/dist/checks/unsafe-vh.js.map +1 -1
  69. package/dist/checks/viewport-support.d.ts +2 -1
  70. package/dist/checks/viewport-support.d.ts.map +1 -1
  71. package/dist/checks/viewport-support.js +13 -8
  72. package/dist/checks/viewport-support.js.map +1 -1
  73. package/dist/index.d.ts +28 -11
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +49 -19
  76. package/dist/index.js.map +1 -1
  77. package/dist/lib/file-source.d.ts +52 -0
  78. package/dist/lib/file-source.d.ts.map +1 -0
  79. package/dist/lib/file-source.js +156 -0
  80. package/dist/lib/file-source.js.map +1 -0
  81. package/dist/lib/gzip.d.ts +8 -0
  82. package/dist/lib/gzip.d.ts.map +1 -0
  83. package/dist/lib/gzip.js +26 -0
  84. package/dist/lib/gzip.js.map +1 -0
  85. package/dist/lib/project-type.d.ts +18 -0
  86. package/dist/lib/project-type.d.ts.map +1 -0
  87. package/dist/lib/project-type.js +34 -0
  88. package/dist/lib/project-type.js.map +1 -0
  89. package/dist/lib/strip.d.ts +60 -0
  90. package/dist/lib/strip.d.ts.map +1 -0
  91. package/dist/lib/strip.js +169 -0
  92. package/dist/lib/strip.js.map +1 -0
  93. package/dist/live/index.d.ts.map +1 -1
  94. package/dist/live/index.js +14 -8
  95. package/dist/live/index.js.map +1 -1
  96. package/package.json +10 -10
  97. package/LICENSE +0 -21
  98. package/dist/checks/brand-fonts.test.d.ts +0 -2
  99. package/dist/checks/brand-fonts.test.d.ts.map +0 -1
  100. package/dist/checks/brand-fonts.test.js +0 -45
  101. package/dist/checks/brand-fonts.test.js.map +0 -1
  102. package/dist/checks/bundle-size.test.d.ts +0 -2
  103. package/dist/checks/bundle-size.test.d.ts.map +0 -1
  104. package/dist/checks/bundle-size.test.js +0 -57
  105. package/dist/checks/bundle-size.test.js.map +0 -1
  106. package/dist/checks/manifest.test.d.ts +0 -2
  107. package/dist/checks/manifest.test.d.ts.map +0 -1
  108. package/dist/checks/manifest.test.js +0 -53
  109. package/dist/checks/manifest.test.js.map +0 -1
  110. package/dist/checks/no-brand-overrides.test.d.ts +0 -2
  111. package/dist/checks/no-brand-overrides.test.d.ts.map +0 -1
  112. package/dist/checks/no-brand-overrides.test.js +0 -102
  113. package/dist/checks/no-brand-overrides.test.js.map +0 -1
  114. package/dist/checks/no-placeholders.test.d.ts +0 -2
  115. package/dist/checks/no-placeholders.test.d.ts.map +0 -1
  116. package/dist/checks/no-placeholders.test.js +0 -46
  117. package/dist/checks/no-placeholders.test.js.map +0 -1
  118. package/dist/checks/no-scroll.test.d.ts +0 -2
  119. package/dist/checks/no-scroll.test.d.ts.map +0 -1
  120. package/dist/checks/no-scroll.test.js +0 -105
  121. package/dist/checks/no-scroll.test.js.map +0 -1
  122. package/dist/checks/no-tracking.test.d.ts +0 -2
  123. package/dist/checks/no-tracking.test.d.ts.map +0 -1
  124. package/dist/checks/no-tracking.test.js +0 -42
  125. package/dist/checks/no-tracking.test.js.map +0 -1
  126. package/dist/checks/unsafe-vh.test.d.ts +0 -2
  127. package/dist/checks/unsafe-vh.test.d.ts.map +0 -1
  128. package/dist/checks/unsafe-vh.test.js +0 -115
  129. package/dist/checks/unsafe-vh.test.js.map +0 -1
  130. package/dist/checks/viewport-support.test.d.ts +0 -2
  131. package/dist/checks/viewport-support.test.d.ts.map +0 -1
  132. package/dist/checks/viewport-support.test.js +0 -63
  133. package/dist/checks/viewport-support.test.js.map +0 -1
  134. package/dist/lib/walk.d.ts +0 -6
  135. package/dist/lib/walk.d.ts.map +0 -1
  136. package/dist/lib/walk.js +0 -35
  137. package/dist/lib/walk.js.map +0 -1
  138. package/dist/live/index.test.d.ts +0 -2
  139. package/dist/live/index.test.d.ts.map +0 -1
  140. package/dist/live/index.test.js +0 -259
  141. package/dist/live/index.test.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"no-tracking.test.js","sourceRoot":"","sources":["../../src/checks/no-tracking.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=unsafe-vh.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unsafe-vh.test.d.ts","sourceRoot":"","sources":["../../src/checks/unsafe-vh.test.ts"],"names":[],"mappings":""}
@@ -1,115 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { checkUnsafeVh } from './unsafe-vh.js';
6
- async function fixture(files) {
7
- const dir = await mkdtemp(join(tmpdir(), 'fas-unsafe-vh-'));
8
- for (const [path, content] of Object.entries(files)) {
9
- const full = join(dir, path);
10
- await mkdir(join(full, '..'), { recursive: true });
11
- await writeFile(full, content);
12
- }
13
- return dir;
14
- }
15
- describe('checkUnsafeVh', () => {
16
- it('passes when no 100vh appears anywhere', async () => {
17
- const dir = await fixture({
18
- 'web/src/index.css': 'body { height: 100svh; }',
19
- 'web/src/App.tsx': 'export default () => <div className="h-screen-not-really" />;',
20
- });
21
- const r = await checkUnsafeVh(dir);
22
- expect(r.status).toBe('pass');
23
- expect(r.detail).toMatch(/no 100vh/);
24
- });
25
- it('warns on a literal 100vh in CSS', async () => {
26
- const dir = await fixture({
27
- 'web/src/index.css': '.full { height: 100vh; }',
28
- });
29
- const r = await checkUnsafeVh(dir);
30
- expect(r.status).toBe('warn');
31
- expect(r.detail).toMatch(/1 occurrence/);
32
- expect(r.suggestions?.join('\n')).toMatch(/web\/src\/index\.css:1.*100vh/);
33
- expect(r.suggestions?.join('\n')).toMatch(/100svh.*100dvh/);
34
- });
35
- it('warns on Tailwind h-screen / min-h-screen / max-h-screen', async () => {
36
- const dir = await fixture({
37
- 'web/src/App.tsx': `
38
- export default () => (
39
- <div className="h-screen">
40
- <header className="min-h-screen" />
41
- <main className="max-h-screen" />
42
- </div>
43
- );
44
- `,
45
- });
46
- const r = await checkUnsafeVh(dir);
47
- expect(r.status).toBe('warn');
48
- expect(r.detail).toMatch(/3 occurrences/);
49
- const suggestionText = r.suggestions?.join('\n') ?? '';
50
- expect(suggestionText).toMatch(/h-screen/);
51
- expect(suggestionText).toMatch(/min-h-screen/);
52
- expect(suggestionText).toMatch(/max-h-screen/);
53
- });
54
- it('respects the `allow-100vh` opt-out comment on the same line', async () => {
55
- const dir = await fixture({
56
- 'web/src/index.css': `
57
- .hero { height: 100vh; /* allow-100vh — intentional, hero stays constant under URL bar */ }
58
- `,
59
- });
60
- const r = await checkUnsafeVh(dir);
61
- expect(r.status).toBe('pass');
62
- });
63
- it('still flags a different line even when one line has the opt-out', async () => {
64
- const dir = await fixture({
65
- 'web/src/index.css': `.a { height: 100vh; /* allow-100vh */ }
66
- .b { height: 100vh; }
67
- `,
68
- });
69
- const r = await checkUnsafeVh(dir);
70
- expect(r.status).toBe('warn');
71
- expect(r.detail).toMatch(/1 occurrence/); // only the un-opt-out line
72
- });
73
- it('does not flag the strings "100svh" / "100dvh" (the recommended fixes)', async () => {
74
- const dir = await fixture({
75
- 'web/src/index.css': `
76
- .a { height: 100svh; }
77
- .b { height: 100dvh; }
78
- `,
79
- });
80
- const r = await checkUnsafeVh(dir);
81
- expect(r.status).toBe('pass');
82
- });
83
- it('does not match identifiers that contain "100vh" as a substring', async () => {
84
- const dir = await fixture({
85
- // `var100vh` and `--my100vhvar` aren't actual unit usage; word
86
- // boundaries must keep us from flagging them.
87
- 'web/src/foo.ts': 'const var100vh = 1; const x = "--my100vhvar";',
88
- });
89
- const r = await checkUnsafeVh(dir);
90
- expect(r.status).toBe('pass');
91
- });
92
- it('caps reported issues at 5 and notes the rest', async () => {
93
- const lines = Array.from({ length: 8 }, (_, i) => `.x${i} { height: 100vh; }`).join('\n');
94
- const dir = await fixture({ 'web/src/index.css': lines });
95
- const r = await checkUnsafeVh(dir);
96
- expect(r.status).toBe('warn');
97
- expect(r.detail).toMatch(/8 occurrences/);
98
- // 5 file:line entries + 1 "...and N more" + 1 final "Replace with..." advice = 7
99
- expect(r.suggestions?.length).toBe(7);
100
- expect(r.suggestions?.[5]).toMatch(/and 3 more/);
101
- });
102
- it('scans CSS, JS, TS, JSX, TSX, HTML — but skips other extensions', async () => {
103
- const dir = await fixture({
104
- 'web/src/index.css': '.a { height: 100vh; }',
105
- 'web/src/App.jsx': 'const x = "h-screen";', // string with the class — still flagged (we can't know intent)
106
- 'docs/notes.md': 'Use 100vh somewhere', // Markdown — should NOT be scanned
107
- 'web/src/foo.scss': '$h: 100vh;',
108
- });
109
- const r = await checkUnsafeVh(dir);
110
- expect(r.status).toBe('warn');
111
- // 3 hits: index.css, App.jsx, foo.scss. notes.md ignored.
112
- expect(r.detail).toMatch(/3 occurrences/);
113
- });
114
- });
115
- //# sourceMappingURL=unsafe-vh.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unsafe-vh.test.js","sourceRoot":"","sources":["../../src/checks/unsafe-vh.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=viewport-support.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"viewport-support.test.d.ts","sourceRoot":"","sources":["../../src/checks/viewport-support.test.ts"],"names":[],"mappings":""}
@@ -1,63 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { checkViewportSupport } from './viewport-support.js';
6
- async function fixture(manifest) {
7
- const dir = await mkdtemp(join(tmpdir(), 'fas-viewport-'));
8
- if (manifest !== null) {
9
- await mkdir(join(dir, 'web', 'public'), { recursive: true });
10
- await writeFile(join(dir, 'web', 'public', 'manifest.json'), JSON.stringify(manifest));
11
- }
12
- return dir;
13
- }
14
- describe('checkViewportSupport', () => {
15
- it('fails when manifest.json is missing', async () => {
16
- const dir = await fixture(null);
17
- const r = await checkViewportSupport(dir);
18
- expect(r.status).toBe('fail');
19
- expect(r.detail).toMatch(/manifest\.json/);
20
- });
21
- it('fails when orientation is missing', async () => {
22
- const dir = await fixture({ name: 'x' });
23
- const r = await checkViewportSupport(dir);
24
- expect(r.status).toBe('fail');
25
- expect(r.suggestions?.join(' ')).toMatch(/orientation/);
26
- });
27
- it('fails when orientation is invalid', async () => {
28
- const dir = await fixture({ name: 'x', orientation: 'rotate' });
29
- const r = await checkViewportSupport(dir);
30
- expect(r.status).toBe('fail');
31
- });
32
- it('warns when min_viewport_width is missing but orientation is valid', async () => {
33
- const dir = await fixture({ name: 'x', orientation: 'any' });
34
- const r = await checkViewportSupport(dir);
35
- expect(r.status).toBe('warn');
36
- expect(r.detail).toMatch(/min_viewport_width/);
37
- });
38
- it('fails when min_viewport_width is below 320', async () => {
39
- const dir = await fixture({ name: 'x', orientation: 'any', min_viewport_width: 280 });
40
- const r = await checkViewportSupport(dir);
41
- expect(r.status).toBe('fail');
42
- });
43
- it('warns on unusual but accepted widths', async () => {
44
- const dir = await fixture({ name: 'x', orientation: 'any', min_viewport_width: 387 });
45
- const r = await checkViewportSupport(dir);
46
- expect(r.status).toBe('warn');
47
- expect(r.detail).toMatch(/unusual/);
48
- });
49
- it('passes for valid orientation + recommended width', async () => {
50
- const dir = await fixture({ name: 'x', orientation: 'any', min_viewport_width: 360 });
51
- const r = await checkViewportSupport(dir);
52
- expect(r.status).toBe('pass');
53
- expect(r.detail).toMatch(/any/);
54
- expect(r.detail).toMatch(/360/);
55
- });
56
- it('passes for portrait-only landscape-only too', async () => {
57
- const dir = await fixture({ name: 'x', orientation: 'portrait', min_viewport_width: 414 });
58
- expect((await checkViewportSupport(dir)).status).toBe('pass');
59
- const dir2 = await fixture({ name: 'x', orientation: 'landscape-primary', min_viewport_width: 768 });
60
- expect((await checkViewportSupport(dir2)).status).toBe('pass');
61
- });
62
- });
63
- //# sourceMappingURL=viewport-support.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"viewport-support.test.js","sourceRoot":"","sources":["../../src/checks/viewport-support.test.ts"],"names":[],"mappings":"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"}
@@ -1,6 +0,0 @@
1
- /**
2
- * Recursive file iteration that skips noise directories. Used by every
3
- * check that needs to scan source files.
4
- */
5
- export declare function walk(dir: string): AsyncGenerator<string>;
6
- //# sourceMappingURL=walk.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../../src/lib/walk.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,wBAAuB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAe/D"}
package/dist/lib/walk.js DELETED
@@ -1,35 +0,0 @@
1
- import { readdir } from 'node:fs/promises';
2
- import { join } from 'node:path';
3
- const SKIP_DIRS = new Set([
4
- '.git',
5
- 'node_modules',
6
- 'dist',
7
- '.next',
8
- '.cache',
9
- '.wrangler',
10
- '.turbo',
11
- ]);
12
- /**
13
- * Recursive file iteration that skips noise directories. Used by every
14
- * check that needs to scan source files.
15
- */
16
- export async function* walk(dir) {
17
- let entries;
18
- try {
19
- entries = await readdir(dir, { withFileTypes: true });
20
- }
21
- catch {
22
- return; // missing dir is not an error here — caller decides
23
- }
24
- for (const entry of entries) {
25
- if (entry.isDirectory()) {
26
- if (SKIP_DIRS.has(entry.name))
27
- continue;
28
- yield* walk(join(dir, entry.name));
29
- }
30
- else if (entry.isFile()) {
31
- yield join(dir, entry.name);
32
- }
33
- }
34
- }
35
- //# sourceMappingURL=walk.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"walk.js","sourceRoot":"","sources":["../../src/lib/walk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,MAAM;IACN,cAAc;IACd,MAAM;IACN,OAAO;IACP,QAAQ;IACR,WAAW;IACX,QAAQ;CACT,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,GAAW;IACrC,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,oDAAoD;IAC9D,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/live/index.test.ts"],"names":[],"mappings":""}
@@ -1,259 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
2
- import { checkNoTrackingLive, checkBrandFontsLive, checkManifestLive, checkBundleSizeLive, checkUnsafeVhLive, auditLive, } from './index.js';
3
- describe('checkNoTrackingLive', () => {
4
- it('passes when HTML is clean of tracker patterns', () => {
5
- const r = checkNoTrackingLive('<html><body>hello</body></html>');
6
- expect(r.status).toBe('pass');
7
- expect(r.detail).toMatch(/no known trackers/);
8
- });
9
- it('flags Google Analytics', () => {
10
- const r = checkNoTrackingLive('<script src="https://google-analytics.com/ga.js"></script>');
11
- expect(r.status).toBe('fail');
12
- expect(r.suggestions?.[0]).toMatch(/Tracking was injected/);
13
- });
14
- it('flags Plausible, Mixpanel, Hotjar variants', () => {
15
- expect(checkNoTrackingLive('<script src="https://plausible.io/script.js">').status).toBe('fail');
16
- expect(checkNoTrackingLive('<div>amplitude tracker</div>').status).toBe('fail');
17
- expect(checkNoTrackingLive('<script>gtag("event")</script>').status).toBe('fail');
18
- expect(checkNoTrackingLive('<script src="https://www.googletagmanager.com/gtm.js">').status).toBe('fail');
19
- expect(checkNoTrackingLive('<script src="//cdn.mixpanel.com/x">').status).toBe('fail');
20
- expect(checkNoTrackingLive('<script src="https://static.hotjar.com/c/hotjar.js">').status).toBe('fail');
21
- expect(checkNoTrackingLive('<script src="https://posthog.com/array.js">').status).toBe('fail');
22
- });
23
- });
24
- describe('checkBrandFontsLive', () => {
25
- it('passes when both Manrope and Fraunces are referenced', () => {
26
- const r = checkBrandFontsLive('<link href="https://fonts.googleapis.com/css2?family=Manrope&family=Fraunces" rel="stylesheet">');
27
- expect(r.status).toBe('pass');
28
- });
29
- it('matches case-insensitively', () => {
30
- const r = checkBrandFontsLive('<style>font-family: manrope, fraunces</style>');
31
- expect(r.status).toBe('pass');
32
- });
33
- it('fails when one or both fonts are missing', () => {
34
- const r1 = checkBrandFontsLive('<link href="...?family=Manrope">');
35
- expect(r1.status).toBe('fail');
36
- expect(r1.detail).toMatch(/Fraunces/);
37
- const r2 = checkBrandFontsLive('<head></head>');
38
- expect(r2.status).toBe('fail');
39
- expect(r2.detail).toMatch(/Manrope.*Fraunces/);
40
- });
41
- });
42
- describe('checkManifestLive', () => {
43
- beforeEach(() => {
44
- vi.stubGlobal('fetch', vi.fn());
45
- });
46
- afterEach(() => {
47
- vi.unstubAllGlobals();
48
- });
49
- it('fails when no <link rel="manifest"> in HTML', async () => {
50
- const r = await checkManifestLive('<html><head></head></html>', 'https://x.example');
51
- expect(r.status).toBe('fail');
52
- expect(r.detail).toMatch(/no <link rel="manifest"/);
53
- });
54
- it('fails when manifest fetch returns non-2xx', async () => {
55
- fetch.mockResolvedValue(new Response('', { status: 404 }));
56
- const html = '<link rel="manifest" href="/manifest.json">';
57
- const r = await checkManifestLive(html, 'https://x.example');
58
- expect(r.status).toBe('fail');
59
- expect(r.detail).toMatch(/404/);
60
- });
61
- it('fails when manifest is missing required fields', async () => {
62
- fetch.mockResolvedValue(new Response(JSON.stringify({ name: 'X' }), {
63
- status: 200,
64
- headers: { 'Content-Type': 'application/json' },
65
- }));
66
- const html = '<link rel="manifest" href="/manifest.json">';
67
- const r = await checkManifestLive(html, 'https://x.example');
68
- expect(r.status).toBe('fail');
69
- expect(r.detail).toMatch(/display.*start_url|start_url.*display/);
70
- });
71
- it('passes when manifest has all required fields', async () => {
72
- fetch.mockResolvedValue(new Response(JSON.stringify({ name: 'X', display: 'standalone', start_url: '/' }), {
73
- status: 200,
74
- }));
75
- const html = '<link rel="manifest" href="/manifest.json">';
76
- const r = await checkManifestLive(html, 'https://x.example');
77
- expect(r.status).toBe('pass');
78
- });
79
- it('resolves manifest URL relative to liveUrl', async () => {
80
- const mockFetch = vi.fn().mockResolvedValue(new Response(JSON.stringify({ name: 'X', display: 'standalone', start_url: '/' }), {
81
- status: 200,
82
- }));
83
- vi.stubGlobal('fetch', mockFetch);
84
- const html = '<link rel="manifest" href="manifest.json">';
85
- await checkManifestLive(html, 'https://app.example/');
86
- // First arg is the URL — should resolve to absolute.
87
- expect(mockFetch).toHaveBeenCalledWith('https://app.example/manifest.json', expect.any(Object));
88
- });
89
- });
90
- describe('checkBundleSizeLive', () => {
91
- beforeEach(() => {
92
- vi.stubGlobal('fetch', vi.fn());
93
- });
94
- afterEach(() => {
95
- vi.unstubAllGlobals();
96
- });
97
- it('returns warn when no /assets/*.js found (non-Vite layout)', async () => {
98
- const r = await checkBundleSizeLive('<html><body></body></html>', 'https://x.example');
99
- expect(r.status).toBe('warn');
100
- expect(r.detail).toMatch(/non-Vite/);
101
- });
102
- it('passes when bundle is comfortably under 300 KB gzipped', async () => {
103
- // 200KB raw → ~57KB approx gzipped — well under.
104
- const small = new ArrayBuffer(200_000);
105
- fetch.mockResolvedValue(new Response(small, { status: 200 }));
106
- const html = '<script src="/assets/index-abc.js"></script>';
107
- const r = await checkBundleSizeLive(html, 'https://x.example');
108
- expect(r.status).toBe('pass');
109
- expect(r.detail).toMatch(/KB gzipped/);
110
- });
111
- it('fails when bundle approximation exceeds 300 KB gzipped', async () => {
112
- // 1.5MB raw → ~430KB approx gzipped — over limit.
113
- const large = new ArrayBuffer(1_500_000);
114
- fetch.mockResolvedValue(new Response(large, { status: 200 }));
115
- const html = '<script src="/assets/index-big.js"></script>';
116
- const r = await checkBundleSizeLive(html, 'https://x.example');
117
- expect(r.status).toBe('fail');
118
- expect(r.detail).toMatch(/over 300 KB/);
119
- });
120
- });
121
- describe('auditLive (integration)', () => {
122
- beforeEach(() => {
123
- vi.stubGlobal('fetch', vi.fn());
124
- });
125
- afterEach(() => {
126
- vi.unstubAllGlobals();
127
- });
128
- it('returns reachable=false + a single fail check when fetch errors', async () => {
129
- fetch.mockRejectedValue(new Error('ECONNREFUSED'));
130
- const r = await auditLive({ appId: 'tip', liveUrl: 'https://tip.example' });
131
- expect(r.reachable).toBe(false);
132
- expect(r.results).toHaveLength(1);
133
- expect(r.results[0].status).toBe('fail');
134
- expect(r.results[0].name).toBe('Reachable');
135
- });
136
- it('returns reachable=false + fail when origin returns 5xx', async () => {
137
- fetch.mockResolvedValue(new Response('boom', { status: 503 }));
138
- const r = await auditLive({ appId: 'tip', liveUrl: 'https://tip.example' });
139
- expect(r.reachable).toBe(false);
140
- expect(r.results[0].detail).toMatch(/HTTP 503/);
141
- });
142
- it('runs all 5 checks when origin is reachable', async () => {
143
- const html = `
144
- <html><head>
145
- <link href="https://fonts.googleapis.com/css2?family=Manrope&family=Fraunces" rel="stylesheet">
146
- <link rel="stylesheet" href="/assets/index-abc.css">
147
- <link rel="manifest" href="/manifest.json">
148
- </head><body>
149
- <script src="/assets/index-abc.js"></script>
150
- </body></html>
151
- `;
152
- let callCount = 0;
153
- fetch.mockImplementation(async (url) => {
154
- callCount++;
155
- if (callCount === 1)
156
- return new Response(html, { status: 200 });
157
- if (url.endsWith('/manifest.json')) {
158
- return new Response(JSON.stringify({ name: 'tip', display: 'standalone', start_url: '/' }), { status: 200 });
159
- }
160
- if (url.endsWith('.css')) {
161
- return new Response('body { height: 100svh; }', { status: 200 });
162
- }
163
- // bundle: small size → pass
164
- return new Response(new ArrayBuffer(150_000), { status: 200 });
165
- });
166
- const r = await auditLive({ appId: 'tip', liveUrl: 'https://tip.example' });
167
- expect(r.reachable).toBe(true);
168
- // 6 results: Reachable + tracking + fonts + manifest + bundle + vh.
169
- // Reachable is recorded on success too so stale fail rows from
170
- // earlier runs get overwritten on the next clean pass.
171
- expect(r.results).toHaveLength(6);
172
- const reachable = r.results.find((c) => c.name === 'Reachable');
173
- expect(reachable?.status).toBe('pass');
174
- const otherStatuses = r.results.filter((c) => c.name !== 'Reachable').map((c) => c.status);
175
- expect(otherStatuses).toEqual(['pass', 'pass', 'pass', 'pass', 'pass']);
176
- });
177
- it('downgrades subrequest-cap errors from fail → warn (not the app\'s fault)', async () => {
178
- fetch.mockRejectedValue(new Error('Too many subrequests by single Worker invocation.'));
179
- const r = await auditLive({ appId: 'tip', liveUrl: 'https://tip.example' });
180
- expect(r.reachable).toBe(false);
181
- expect(r.results).toHaveLength(1);
182
- expect(r.results[0].name).toBe('Reachable');
183
- expect(r.results[0].status).toBe('warn');
184
- expect(r.results[0].detail).toMatch(/subrequest cap/);
185
- });
186
- it('stamps checkedAt and preserves appId', async () => {
187
- fetch.mockRejectedValue(new Error('x'));
188
- const before = Date.now();
189
- const r = await auditLive({ appId: 'my-app', liveUrl: 'https://my.example' });
190
- const after = Date.now();
191
- expect(r.appId).toBe('my-app');
192
- expect(r.liveUrl).toBe('https://my.example');
193
- expect(r.checkedAt).toBeGreaterThanOrEqual(before);
194
- expect(r.checkedAt).toBeLessThanOrEqual(after);
195
- });
196
- });
197
- describe('checkUnsafeVhLive', () => {
198
- beforeEach(() => {
199
- vi.stubGlobal('fetch', vi.fn());
200
- });
201
- afterEach(() => {
202
- vi.unstubAllGlobals();
203
- });
204
- it('warns when no <link rel="stylesheet"> exists in HTML', async () => {
205
- const r = await checkUnsafeVhLive('<html><body></body></html>', 'https://x.example');
206
- expect(r.status).toBe('warn');
207
- expect(r.detail).toMatch(/no.*stylesheet/);
208
- });
209
- it('finds the stylesheet href regardless of attribute order (rel before href)', async () => {
210
- fetch.mockResolvedValue(new Response('body { height: 100svh; }', { status: 200 }));
211
- const html = '<link rel="stylesheet" href="/assets/index.css">';
212
- const r = await checkUnsafeVhLive(html, 'https://x.example');
213
- expect(r.status).toBe('pass');
214
- });
215
- it('finds the stylesheet href regardless of attribute order (href before rel)', async () => {
216
- fetch.mockResolvedValue(new Response('body { height: 100svh; }', { status: 200 }));
217
- const html = '<link href="/assets/index.css" rel="stylesheet">';
218
- const r = await checkUnsafeVhLive(html, 'https://x.example');
219
- expect(r.status).toBe('pass');
220
- });
221
- it('warns when CSS contains 100vh', async () => {
222
- fetch.mockResolvedValue(new Response('.full { height: 100vh; padding: 100vh; }', { status: 200 }));
223
- const html = '<link rel="stylesheet" href="/assets/index.css">';
224
- const r = await checkUnsafeVhLive(html, 'https://x.example');
225
- expect(r.status).toBe('warn');
226
- expect(r.detail).toMatch(/2 occurrence\(s\) of 100vh/);
227
- expect(r.suggestions?.join('\n')).toMatch(/100svh.*100dvh/);
228
- });
229
- it('passes when CSS uses 100svh / 100dvh exclusively', async () => {
230
- fetch.mockResolvedValue(new Response('a{height:100svh}b{height:100dvh}', { status: 200 }));
231
- const html = '<link rel="stylesheet" href="/assets/index.css">';
232
- const r = await checkUnsafeVhLive(html, 'https://x.example');
233
- expect(r.status).toBe('pass');
234
- });
235
- it('does not match identifier-like substrings (word boundary on the unit)', async () => {
236
- // `--my100vhvar` and `var100vh1` aren't actual unit usage; the
237
- // word-boundary anchors on the regex literal must keep us from
238
- // flagging them.
239
- fetch.mockResolvedValue(new Response('.x { --my100vhvar: 0; } .y { content: "var100vh1"; }', { status: 200 }));
240
- const html = '<link rel="stylesheet" href="/assets/index.css">';
241
- const r = await checkUnsafeVhLive(html, 'https://x.example');
242
- expect(r.status).toBe('pass');
243
- });
244
- it('warns (not fail) on subrequest cap errors so audit-Worker noise does not flip badges', async () => {
245
- fetch.mockRejectedValue(new Error('Too many subrequests by single Worker invocation'));
246
- const html = '<link rel="stylesheet" href="/assets/index.css">';
247
- const r = await checkUnsafeVhLive(html, 'https://x.example');
248
- expect(r.status).toBe('warn');
249
- expect(r.detail).toMatch(/subrequest cap/);
250
- });
251
- it('warns on non-200 CSS fetch response', async () => {
252
- fetch.mockResolvedValue(new Response('', { status: 404 }));
253
- const html = '<link rel="stylesheet" href="/assets/index.css">';
254
- const r = await checkUnsafeVhLive(html, 'https://x.example');
255
- expect(r.status).toBe('warn');
256
- expect(r.detail).toMatch(/HTTP 404/);
257
- });
258
- });
259
- //# sourceMappingURL=index.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/live/index.test.ts"],"names":[],"mappings":"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"}