1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
// @ts-check
import * as assert from 'node:assert/strict';
import { after, before, beforeEach, describe, it } from 'node:test';
import { parseHTML } from 'linkedom';
import { loadFixture } from './test-utils.js';
/**
* @template {Record<K, (...args: any[]) => void>} T
* @template {keyof T} K
*/
class MockFunction {
/** @type {Parameters<T[K]>[]} */
calls = [];
/**
* @param {T} object
* @param {K} property
*/
constructor(object, property) {
this.object = object;
this.property = property;
this.original = object[property];
object[property] = /** @param {Parameters<T[K]>} args */ (...args) => {
this.calls.push(args);
};
}
restore() {
this.object[this.property] = this.original;
}
reset() {
this.calls = [];
}
}
describe('Web Vitals integration basics', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
/** @type {import('./test-utils').DevServer} */
let devServer;
/** @type {MockFunction<Console, 'error'>} */
let consoleErrorMock;
before(async () => {
consoleErrorMock = new MockFunction(console, 'error');
fixture = await loadFixture({ root: './fixtures/basics/' });
devServer = await fixture.startDevServer({});
});
after(async () => {
consoleErrorMock.restore();
await devServer.stop();
});
beforeEach(() => {
consoleErrorMock.reset();
});
it('adds a meta tag to the page', async () => {
const html = await fixture.fetch('/', {}).then((res) => res.text());
const { document } = parseHTML(html);
const meta = document.querySelector('head > meta[name="x-astro-vitals-route"]');
assert.ok(meta);
assert.equal(meta.getAttribute('content'), '/');
});
it('adds a meta tag using the route pattern to the page', async () => {
const html = await fixture.fetch('/test', {}).then((res) => res.text());
const { document } = parseHTML(html);
const meta = document.querySelector('head > meta[name="x-astro-vitals-route"]');
assert.ok(meta);
assert.equal(meta.getAttribute('content'), '/[dynamic]');
});
it('returns a 200 response even when bad data is sent to the injected endpoint', async () => {
{
// bad data
const res = await fixture.fetch('/_web-vitals', { method: 'POST', body: 'garbage' });
assert.equal(res.status, 200);
}
{
// no data
const res = await fixture.fetch('/_web-vitals', { method: 'POST', body: '[]' });
assert.equal(res.status, 200);
}
assert.equal(consoleErrorMock.calls.length, 2);
});
it('validates data sent to the injected endpoint with Zod', async () => {
const res = await fixture.fetch('/_web-vitals', { method: 'POST', body: '[{}]' });
assert.equal(res.status, 200);
const call = consoleErrorMock.calls[0][0];
assert.ok(call instanceof Error);
assert.equal(call.name, 'ZodError');
});
it('inserts data via the injected endpoint', async () => {
const res = await fixture.fetch('/_web-vitals', {
method: 'POST',
body: JSON.stringify([
{
pathname: '/',
route: '/',
name: 'CLS',
id: 'v3-1711484350895-3748043125387',
value: 0,
rating: 'good',
},
]),
});
assert.equal(res.status, 200);
assert.equal(
consoleErrorMock.calls.length,
0,
'Endpoint logged errors:\n' + consoleErrorMock.calls[0]?.join(' ')
);
});
});
|