Skip to content
Merged
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
260 changes: 130 additions & 130 deletions test/css/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* data because that view is a strict subset of the curated view.
*/

import { describe, it, before } from 'node:test';
import { describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
Expand All @@ -28,158 +28,158 @@ const cssValues = [
{ type: 'value space', prop: 'values', value: 'value' }
];

describe(`The curated view of CSS extracts`, () => {
before(async () => {
const all = await css.listAll({ folder: curatedFolder });
const baseProperties = {};
const basePropertiesInDeltaSpecs = {};
const extendedProperties = {};
const selectors = {};
const valuespaces = {};
describe(`The curated view of CSS extracts`, async () => {
let all;
try {
all = await css.listAll({ folder: curatedFolder });
} catch (err) {
it('contains valid JSON data', () => {throw err;});
}
const baseProperties = {};
const basePropertiesInDeltaSpecs = {};
const extendedProperties = {};
const selectors = {};
const valuespaces = {};

for (const [shortname, data] of Object.entries(all)) {
describe(`The CSS extract for ${shortname} in the curated view`, () => {
it('contains a link to the underlying spec', async () => {
assert(data);
assert(data.spec);
assert(data.spec.title);
});
for (const [shortname, data] of Object.entries(all)) {
describe(`The CSS extract for ${shortname} in the curated view`, () => {
it('contains a link to the underlying spec', async () => {
assert(data);
assert(data.spec);
assert(data.spec.title);
});

const spec = index.results.find(s => s.nightly?.url === data.spec.url);
for (const { type, prop, value } of cssValues) {
for (const desc of data[prop]) {
const name = desc.name;
if ((type === 'property') && (spec.seriesComposition !== 'delta') && !desc.newValues) {
if (!baseProperties[name]) {
baseProperties[name] = [];
}
baseProperties[name].push({ spec: data.spec, dfn: desc });
}
else if ((type === 'property') && (spec.seriesComposition === 'delta') && !desc.newValues) {
if (!basePropertiesInDeltaSpecs[name]) {
basePropertiesInDeltaSpecs[name] = [];
}
basePropertiesInDeltaSpecs[name].push({ spec: data.spec, dfn: desc });
}
else if ((type === 'extended property') && desc[value]) {
if (!extendedProperties[name]) {
extendedProperties[name] = [];
}
extendedProperties[name].push({ spec: data.spec, dfn: desc });
const spec = index.results.find(s => s.nightly?.url === data.spec.url);
for (const { type, prop, value } of cssValues) {
for (const desc of data[prop]) {
const name = desc.name;
if ((type === 'property') && (spec.seriesComposition !== 'delta') && !desc.newValues) {
if (!baseProperties[name]) {
baseProperties[name] = [];
}
else if ((type === 'selector') && (spec.seriesComposition !== 'delta')) {
if (!selectors[name]) {
selectors[name] = [];
}
selectors[name].push({ spec: data.spec, dfn: desc });
baseProperties[name].push({ spec: data.spec, dfn: desc });
}
else if ((type === 'property') && (spec.seriesComposition === 'delta') && !desc.newValues) {
if (!basePropertiesInDeltaSpecs[name]) {
basePropertiesInDeltaSpecs[name] = [];
}
else if ((type === 'value space') && (spec.seriesComposition !== 'delta')) {
if (!valuespaces[name]) {
valuespaces[name] = [];
}
valuespaces[name].push({ spec: data.spec, dfn: desc });
basePropertiesInDeltaSpecs[name].push({ spec: data.spec, dfn: desc });
}
else if ((type === 'extended property') && desc[value]) {
if (!extendedProperties[name]) {
extendedProperties[name] = [];
}
if (!desc[value]) {
continue;
extendedProperties[name].push({ spec: data.spec, dfn: desc });
}
else if ((type === 'selector') && (spec.seriesComposition !== 'delta')) {
if (!selectors[name]) {
selectors[name] = [];
}
if (type === 'descriptor') {
for (const dfn of desc[value]) {
it(`defines a valid ${type} "${dfn.name}" for at-rule "${name}"`, () => {
assert.strictEqual(dfn.for, name);
assert.doesNotThrow(() => {
const ast = definitionSyntax.parse(dfn.value);
assert(ast.type);
}, `Invalid definition value: ${dfn.value}`);
});
}
selectors[name].push({ spec: data.spec, dfn: desc });
}
else if ((type === 'value space') && (spec.seriesComposition !== 'delta')) {
if (!valuespaces[name]) {
valuespaces[name] = [];
}
else {
it(`defines a valid ${type} "${name}"`, () => {
valuespaces[name].push({ spec: data.spec, dfn: desc });
}
if (!desc[value]) {
continue;
}
if (type === 'descriptor') {
for (const dfn of desc[value]) {
it(`defines a valid ${type} "${dfn.name}" for at-rule "${name}"`, () => {
assert.strictEqual(dfn.for, name);
assert.doesNotThrow(() => {
const ast = definitionSyntax.parse(desc[value]);
const ast = definitionSyntax.parse(dfn.value);
assert(ast.type);
}, `Invalid definition value: ${desc[value]}`);
});
};

// All CSS values should link back to the spec, except:
// - properties that extend a base property
// - at-rulesdefined elsewhere (and present only because the spec
// defines new descriptors for them)
// - properties in delta specs that completely override the base
// definition - currently enforced more restrictively as
// "the 'contain' property in css-contain-3", to better track such
// occurrences that should remain an exception to the exception rule!
if (!desc.newValues &&
(prop !== 'atrules' || desc.value || desc.prose) &&
!(prop === 'properties' && name === 'contain' && spec.shortname === 'css-contain-3')) {
it(`has a link back to the spec for ${type} "${name}"`, () => {
assert(desc.href);
assert(desc.href.includes('#'));
}, `Invalid definition value: ${dfn.value}`);
});
}
}
else {
it(`defines a valid ${type} "${name}"`, () => {
assert.doesNotThrow(() => {
const ast = definitionSyntax.parse(desc[value]);
assert(ast.type);
}, `Invalid definition value: ${desc[value]}`);
});
};

if (desc.values) {
for (const value of desc.values) {
if (!value.value) {
continue;
}
it(`defines a valid value "${value.name}" for ${type} "${name}"`, () => {
assert.doesNotThrow(() => {
const ast = definitionSyntax.parse(value.value);
assert(ast.type);
}, `Invalid definition value: ${value.value}`);
});
// All CSS values should link back to the spec, except:
// - properties that extend a base property
// - at-rulesdefined elsewhere (and present only because the spec
// defines new descriptors for them)
// - properties in delta specs that completely override the base
// definition - currently enforced more restrictively as
// "the 'contain' property in css-contain-3", to better track such
// occurrences that should remain an exception to the exception rule!
if (!desc.newValues &&
(prop !== 'atrules' || desc.value || desc.prose) &&
!(prop === 'properties' && name === 'contain' && spec.shortname === 'css-contain-3')) {
it(`has a link back to the spec for ${type} "${name}"`, () => {
assert(desc.href);
assert(desc.href.includes('#'));
});
}

it(`has a link back to the spec for value "${value.name}" for ${type} "${name}"`, () => {
assert(value.href);
assert(value.href.includes('#'));
});
if (desc.values) {
for (const value of desc.values) {
if (!value.value) {
continue;
}
it(`defines a valid value "${value.name}" for ${type} "${name}"`, () => {
assert.doesNotThrow(() => {
const ast = definitionSyntax.parse(value.value);
assert(ast.type);
}, `Invalid definition value: ${value.value}`);
});

it(`has a link back to the spec for value "${value.name}" for ${type} "${name}"`, () => {
assert(value.href);
assert(value.href.includes('#'));
});
}
}
}
});
}

describe(`Looking at CSS properties, the curated view`, () => {
for (const [name, dfns] of Object.entries(baseProperties)) {
it(`contains only one "${name}" property definition`, () => {
assert.strictEqual(dfns.length, 1,
`defined in ${dfns.map(d => d.spec.title).join(', ')} (${dfns.map(d => d.spec.url).join(', ')})`);
});
}
});
}

describe(`Looking at CSS selectors, the curated view`, () => {
for (const [name, dfns] of Object.entries(selectors)) {
it(`contains only one "${name}" selector definition`, () => {
assert.strictEqual(dfns.length, 1,
`defined in ${dfns.map(d => d.spec.title).join(', ')} (${dfns.map(d => d.spec.url).join(', ')})`);
});
}
});
describe(`Looking at CSS properties, the curated view`, () => {
for (const [name, dfns] of Object.entries(baseProperties)) {
it(`contains only one "${name}" property definition`, () => {
assert.strictEqual(dfns.length, 1,
`defined in ${dfns.map(d => d.spec.title).join(', ')} (${dfns.map(d => d.spec.url).join(', ')})`);
});
}
});

describe(`Looking at CSS selectors, the curated view`, () => {
for (const [name, dfns] of Object.entries(selectors)) {
it(`contains only one "${name}" selector definition`, () => {
assert.strictEqual(dfns.length, 1,
`defined in ${dfns.map(d => d.spec.title).join(', ')} (${dfns.map(d => d.spec.url).join(', ')})`);
});
}
});


describe(`Looking at extended CSS properties, the curated view`, () => {
for (const [name, dfns] of Object.entries(extendedProperties)) {
it(`contains a base definition for the "${name}" property`, () => {
assert(baseProperties[name] || basePropertiesInDeltaSpecs[name], 'no base definition found');
});
}
});
describe(`Looking at extended CSS properties, the curated view`, () => {
for (const [name, dfns] of Object.entries(extendedProperties)) {
it(`contains a base definition for the "${name}" property`, () => {
assert(baseProperties[name] || basePropertiesInDeltaSpecs[name], 'no base definition found');
});
}
});

describe(`Looking at CSS valuespaces, the curated view`, () => {
for (const [name, dfns] of Object.entries(valuespaces)) {
it(`contains only one "${name}" valuespace definition`, () => {
assert.strictEqual(dfns.length, 1,
`defined in ${dfns.map(d => d.spec.title).join(', ')} (${dfns.map(d => d.spec.url).join(', ')})`);
});
}
});
describe(`Looking at CSS valuespaces, the curated view`, () => {
for (const [name, dfns] of Object.entries(valuespaces)) {
it(`contains only one "${name}" valuespace definition`, () => {
assert.strictEqual(dfns.length, 1,
`defined in ${dfns.map(d => d.spec.title).join(', ')} (${dfns.map(d => d.spec.url).join(', ')})`);
});
}
});

// Dummy test needed for "before" to run and register late tests
// (test will fail if before function throws, e.g. because data is invalid)
it('contains valid JSON data', () => {});
});
57 changes: 28 additions & 29 deletions test/elements/consistency.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Test the consistency of elements extracts with IDL extracts.
*
*
* The tests run against the curated and package views of the data. An extract
* that passes a test in the curated view may fail the same test in the package
* view because of some missing IDL definition in that view.
*/

import { describe, it, before } from 'node:test';
import { describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
Expand All @@ -26,37 +26,36 @@ const views = [
];

views.forEach(({ name, folder }) => {
describe(`The ${name} view of elements extracts`, () => {
before(async () => {
// Create a set of well-known interfaces
const allIdl = await idl.parseAll({ folder: path.join(folder, 'idl') });
const interfaces = new Set();
for (const [shortname, ast] of Object.entries(allIdl)) {
for (const dfn of ast) {
if (dfn.name) {
interfaces.add(dfn.name);
}
describe(`The ${name} view of elements extracts`, async () => {
let allIdl;
try {
allIdl = await idl.parseAll({ folder: path.join(folder, 'idl') });
} catch (err) {
it('contains valid JSON data', () => {throw err;});
}
const interfaces = new Set();
for (const [shortname, ast] of Object.entries(allIdl)) {
for (const dfn of ast) {
if (dfn.name) {
interfaces.add(dfn.name);
}
}
}

const allElements = await elements.listAll({ folder: path.join(folder, 'elements') });
for (const [shortname, data] of Object.entries(allElements)) {
describe(`The elements extract for ${shortname} in the ${name} view`, () => {
for (const el of data.elements) {
if (!el.interface) {
continue;
}
it(`links to a well-known interface for "${el.name}"`, () => {
assert(interfaces.has(el.interface), `Unknown interface "${el.interface}"`);
});
const allElements = await elements.listAll({ folder: path.join(folder, 'elements') });
for (const [shortname, data] of Object.entries(allElements)) {
describe(`The elements extract for ${shortname} in the ${name} view`, () => {
for (const el of data.elements) {
if (!el.interface) {
continue;
}
});
}
});

// Dummy test needed for "before" to run and register late tests
// (test will fail if before function throws, e.g. because data is invalid)
it('contains valid JSON data', () => {});
it(`links to a well-known interface for "${el.name}"`, () => {
assert(interfaces.has(el.interface), `Unknown interface "${el.interface}"`);
});
}
});
}
});

});

Loading
Loading