* Chore: Add move most types from rrweb to @rrweb/types package * Split off type imports * Split off type import to its own line * Get vite to generate type definitions * Apply formatting changes * noEmit not allowed in tsconfig, moved it to build step * Migrate rrdom-nodejs build to vite * Apply formatting changes * Migrate rrweb-snapshot to vite * Unify configs * Chore: Migrate rrdom to vite Turns out what we where doing by overwriting `public textContent: string | undefined` as a getter in a subclass is something that isn't allowed in typescript. Because we where using `// @ts-ignore` to hide this error our bundler chose to allow the overwrite. Vite choses to disallow the overwrite making all subclasses' `textContent` undefined. To mitigate this we're using an abstract class, which does allow sub classes to decide if they wan't to use getters or not. * Chore: Migrate rrweb to vite WIP * build:browser was removed (for now) * BREAKING: moved rrweb-plugin-console to its own npm module This removes console from rrweb-all.js * Support cjs files in startServer * Move canvas-webrtc plugin to its own package * Chore: move sequential-id plugin to its own package * Chore: Configure rrweb's vite bundling * `Id` had lowercase `d` before, making it lowercase again * Test: Move console tests to their own package * remove unused utils from rrdom * pull in latest version of master something when wrong earlier when resolving merge conflicts, this should be correct * Fix type casting issue in diff.ts * Fix typo * Fix duplicate entries in package.json and tsconfig.json * Apply formatting changes * Update dependencies in package.json files * Update dependencies to use Vite 5.2.8 in package.json files * Get tests passing for rrdom `apply virtual style rules to node` tests need to be moved to rrweb to avoid circular dependencies * Fix image loading issue in integration tests * Move pack/unpack to its own @rrweb/packer module * Get tests to work in rrdom-nodejs * Port tests in rrweb-snapshot to vitest and fix them * Fix tests for rrweb-plugin-console-record * Add @rrweb/all package * Fix publint and attw errors for rrdom and @rrweb/types * Use shared vitest.config.ts in rrweb-snapshot package * Fix publint and attw issues for rrweb-snapshot * Export `ReplayPlugin` type directly from rrweb * Fix publint and attw issues for packages * Fix publint & attw issue. I was bumping into this issue:3729bc2a3c/docs/problems/NoResolution.mdAnd had to choose one of these three methods described here: https://github.com/andrewbranch/example-subpath-exports-ts-compat?tab=readme-ov-file#typescript-friendly-strategies-for-packagejson-subpath-exports-compatibility And I ended up going for the method described here:1ffe3425b0/examples/node_modules/package-json-redirects (package-json-redirects)The redirect method seemed the least invasive and most effective. * Fix publint & attw issue. I was bumping into this issue:3729bc2a3c/docs/problems/NoResolution.mdAnd had to choose one of these three methods described here: https://github.com/andrewbranch/example-subpath-exports-ts-compat?tab=readme-ov-file#typescript-friendly-strategies-for-packagejson-subpath-exports-compatibility And I ended up going for the method described here:1ffe3425b0/examples/node_modules/package-json-redirects (package-json-redirects)The redirect method seemed the least invasive and most effective. * move some rrdom tests that require rrweb to rrweb package * Use pre-jest 29 syntax for snapshotting * get rrweb passing publint and attw * const enum does not work with isolated modules flag * Fix script tag type in webgl.test.ts.snap and update rrweb.umd.cjs path in webgl.test.ts * Fix paths * Move tests for console record plugin and fix bundle path * Fix tests for rrweb * pack integration tests were moved to @rrweb/all * Update rrweb bundle path in test files * Fix flaky scroll emit from test * Migrate rrweb's tests over to vitest and make them pass * Make sure benchmarks & updating tests work * Remove jest from rrweb * Fix paths * always use rrweb's own cssom * Update tsconfig.json for rrweb-plugin-sequential-id-record Fixes this error: Error: @rrweb/rrweb-plugin-sequential-id-record:prepublish: tsconfig.json(9,5): error TS6377: Cannot write file '/home/runner/work/rrweb/rrweb/tsconfig.tsbuildinfo' because it will overwrite '.tsbuildinfo' file generated by referenced project '/home/runner/work/rrweb/rrweb/packages/rrweb' * Add tsbuildinfo config to extended tsconfig files * Move rrdom over to vitest * Apply formatting changes * Update rrweb imports to use the new package structure * extend rrweb-snapshot's tsconfig from monorepo base config * extend @rrweb/types's tsconfig from monorepo base config * extend rrdom's tsconfig from monorepo base config * extend rrdom-nodejs's tsconfig from monorepo base config * extend web-extension's tsconfig from monorepo base config * unify tsconfigs * Continue when tests fail * Add stricter type checking * Add check-types global command * remove jest * Remove unused code * Add check-types command to build script * Fix linting issues * Add setup Chrome action for CI/CD workflow * Update puppeteer version in package.json for rrweb * Update Chrome setup in CI/CD workflow * Update Chrome setup in CI/CD workflow * Add Chrome setup and test cache location * Update CI/CD workflow to test chrome cache location * Add chrome installation step to CI/CD workflow * Update Puppeteer configuration for headless testing * Update dependencies and workflow configuration * Use same version of chrome on CI as is run locally * Use version of chrome that seems to work with rrdom tests * Try using puppeteerrc to define chrome version * Add .cache directory to .gitignore * Move global flag to vitest config * Update puppeteer version to 20.9.0 * Update console log messages in rrweb-plugin-console-record for new puppeteer version * Remove redundant Chrome setup from CI/CD workflow * Add minification and umd for all built files * Update import paths for rrweb dist files * Add @rrweb/replay and @rrweb/record * Add script to lint packages * Apply formatting changes * exclude styles export from typescript package type checking * WIP Move rrweb-player over to vite * Apply formatting changes * chore: Update rrweb plugin import paths * Remove rollup from rrweb-player * Fix typing issues * Fix typing issues * chore: Update rrweb-player to use vite for build process * Apply formatting changes * chore: Export Player class in rrweb-player/src/main.ts Makes attw happy * Apply formatting changes * Gets wiped by yarn workspaces-to-typescript-project-references * Add .eslintignore and .eslintrc.cjs files for rrweb-player package * Apply formatting changes * Update dependencies in rrweb-player/package.json * Apply formatting changes * chore: Update eslint configuration for rrweb-player package * Apply formatting changes * chore: Remove unused files from rrweb-player package * Apply formatting changes * chore: Update rrweb-player import path to use rrweb-player.cjs * chore: Update addEventListener signature in rrweb-player * Apply formatting changes * Add .eslintignore and update .gitignore files for to root * Apply formatting changes * Update documentation * Update @rrweb/types package description * Apply formatting changes * Update build and run commands in CONTRIBUTING.md * Apply formatting changes * Update package versions to 2.0.0-alpha.13 * Apply formatting changes * Apply formatting changes * Fix import statement in media/index.ts * Apply formatting changes * chore: Update .gitignore to exclude build and dist directories * Apply formatting changes * Apply formatting changes * Migrate setTimeout to vitest * Apply formatting changes * Apply formatting changes * Fix isNativeShadowDom function signature in utils.ts * try out jsr * Apply formatting changes * Update package versions to 2.0.0-alpha.14 * Apply formatting changes * Fix name of rrwebSnapshot object * Apply formatting changes * Remove unused lock files * Apply formatting changes * Update rrweb bundle path to use umd.cjs format * Apply formatting changes * Trigger tests to run again * Rename snapshots for vitest * Apply formatting changes * Ping CI * Apply formatting changes * Ping CI * Apply formatting changes * Ignore files generated by svelte-kit for prettier * Correct Player object
256 lines
7.3 KiB
TypeScript
256 lines
7.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { parse, Rule, Media } from '../src/css';
|
|
import { fixSafariColons, escapeImportStatement } from './../src/utils';
|
|
|
|
describe('css parser', () => {
|
|
it('should save the filename and source', () => {
|
|
const css = 'booty {\n size: large;\n}\n';
|
|
const ast = parse(css, {
|
|
source: 'booty.css',
|
|
});
|
|
|
|
expect(ast.stylesheet!.source).toEqual('booty.css');
|
|
|
|
const position = ast.stylesheet!.rules[0].position!;
|
|
expect(position.start).toBeTruthy();
|
|
expect(position.end).toBeTruthy();
|
|
expect(position.source).toEqual('booty.css');
|
|
expect(position.content).toEqual(css);
|
|
});
|
|
|
|
it('should throw when a selector is missing', () => {
|
|
expect(() => {
|
|
parse('{size: large}');
|
|
}).toThrow();
|
|
|
|
expect(() => {
|
|
parse('b { color: red; }\n{ color: green; }\na { color: blue; }');
|
|
}).toThrow();
|
|
});
|
|
|
|
it('should throw when a broken comment is found', () => {
|
|
expect(() => {
|
|
parse('thing { color: red; } /* b { color: blue; }');
|
|
}).toThrow();
|
|
|
|
expect(() => {
|
|
parse('/*');
|
|
}).toThrow();
|
|
|
|
/* Nested comments should be fine */
|
|
expect(() => {
|
|
parse('/* /* */');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should allow empty property value', () => {
|
|
expect(() => {
|
|
parse('p { color:; }');
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should not throw with silent option', () => {
|
|
expect(() => {
|
|
parse('thing { color: red; } /* b { color: blue; }', { silent: true });
|
|
}).not.toThrow();
|
|
});
|
|
|
|
it('should list the parsing errors and continue parsing', () => {
|
|
const result = parse(
|
|
'foo { color= red; } bar { color: blue; } baz {}} boo { display: none}',
|
|
{
|
|
silent: true,
|
|
source: 'foo.css',
|
|
},
|
|
);
|
|
|
|
const rules = result.stylesheet!.rules;
|
|
expect(rules.length).toBeGreaterThan(2);
|
|
|
|
const errors = result.stylesheet!.parsingErrors!;
|
|
expect(errors.length).toEqual(2);
|
|
|
|
expect(errors[0]).toHaveProperty('message');
|
|
expect(errors[0]).toHaveProperty('reason');
|
|
expect(errors[0]).toHaveProperty('filename');
|
|
expect(errors[0]).toHaveProperty('line');
|
|
expect(errors[0]).toHaveProperty('column');
|
|
expect(errors[0]).toHaveProperty('source');
|
|
expect(errors[0].filename).toEqual('foo.css');
|
|
});
|
|
|
|
it('should parse selector with comma nested inside ()', () => {
|
|
const result = parse(
|
|
'[_nghost-ng-c4172599085]:not(.fit-content).aim-select:hover:not(:disabled, [_nghost-ng-c4172599085]:not(.fit-content).aim-select--disabled, [_nghost-ng-c4172599085]:not(.fit-content).aim-select--invalid, [_nghost-ng-c4172599085]:not(.fit-content).aim-select--active) { border-color: rgb(84, 84, 84); }',
|
|
);
|
|
|
|
expect(result.parent).toEqual(null);
|
|
|
|
const rules = result.stylesheet!.rules;
|
|
expect(rules.length).toEqual(1);
|
|
|
|
let rule = rules[0] as Rule;
|
|
expect(rule.parent).toEqual(result);
|
|
expect(rule.selectors?.length).toEqual(1);
|
|
|
|
let decl = rule.declarations![0];
|
|
expect(decl.parent).toEqual(rule);
|
|
});
|
|
|
|
it('parses { and } in attribute selectors correctly', () => {
|
|
const result = parse('foo[someAttr~="{someId}"] { color: red; }');
|
|
const rules = result.stylesheet!.rules;
|
|
|
|
expect(rules.length).toEqual(1);
|
|
|
|
const rule = rules[0] as Rule;
|
|
|
|
expect(rule.selectors![0]).toEqual('foo[someAttr~="{someId}"]');
|
|
});
|
|
|
|
it('should set parent property', () => {
|
|
const result = parse(
|
|
'thing { test: value; }\n' +
|
|
'@media (min-width: 100px) { thing { test: value; } }',
|
|
);
|
|
|
|
expect(result.parent).toEqual(null);
|
|
|
|
const rules = result.stylesheet!.rules;
|
|
expect(rules.length).toEqual(2);
|
|
|
|
let rule = rules[0] as Rule;
|
|
expect(rule.parent).toEqual(result);
|
|
expect(rule.declarations!.length).toEqual(1);
|
|
|
|
let decl = rule.declarations![0];
|
|
expect(decl.parent).toEqual(rule);
|
|
|
|
const media = rules[1] as Media;
|
|
expect(media.parent).toEqual(result);
|
|
expect(media.rules!.length).toEqual(1);
|
|
|
|
rule = media.rules![0] as Rule;
|
|
expect(rule.parent).toEqual(media);
|
|
|
|
expect(rule.declarations!.length).toEqual(1);
|
|
decl = rule.declarations![0];
|
|
expect(decl.parent).toEqual(rule);
|
|
});
|
|
|
|
it('parses : in attribute selectors correctly', () => {
|
|
const out1 = fixSafariColons('[data-foo] { color: red; }');
|
|
expect(out1).toEqual('[data-foo] { color: red; }');
|
|
|
|
const out2 = fixSafariColons('[data-foo:other] { color: red; }');
|
|
expect(out2).toEqual('[data-foo\\:other] { color: red; }');
|
|
|
|
const out3 = fixSafariColons('[data-aa\\:other] { color: red; }');
|
|
expect(out3).toEqual('[data-aa\\:other] { color: red; }');
|
|
});
|
|
|
|
it('parses nested commas in selectors correctly', () => {
|
|
const result = parse(
|
|
`
|
|
body > ul :is(li:not(:first-of-type) a:hover, li:not(:first-of-type).active a) {
|
|
background: red;
|
|
}
|
|
`,
|
|
);
|
|
expect((result.stylesheet!.rules[0] as Rule)!.selectors!.length).toEqual(1);
|
|
|
|
const trickresult = parse(
|
|
`
|
|
li[attr="weirdly("] a:hover, li[attr="weirdly)"] a {
|
|
background-color: red;
|
|
}
|
|
`,
|
|
);
|
|
expect(
|
|
(trickresult.stylesheet!.rules[0] as Rule)!.selectors!.length,
|
|
).toEqual(2);
|
|
|
|
const weirderresult = parse(
|
|
`
|
|
li[attr="weirder\\"("] a:hover, li[attr="weirder\\")"] a {
|
|
background-color: red;
|
|
}
|
|
`,
|
|
);
|
|
expect(
|
|
(weirderresult.stylesheet!.rules[0] as Rule)!.selectors!.length,
|
|
).toEqual(2);
|
|
|
|
const commainstrresult = parse(
|
|
`
|
|
li[attr="has,comma"] a:hover {
|
|
background-color: red;
|
|
}
|
|
`,
|
|
);
|
|
expect(
|
|
(commainstrresult.stylesheet!.rules[0] as Rule)!.selectors!.length,
|
|
).toEqual(1);
|
|
});
|
|
|
|
it('parses imports with quotes correctly', () => {
|
|
const out1 = escapeImportStatement({
|
|
cssText: `@import url("/foo.css;900;800"");`,
|
|
href: '/foo.css;900;800"',
|
|
media: {
|
|
length: 0,
|
|
},
|
|
layerName: null,
|
|
supportsText: null,
|
|
} as unknown as CSSImportRule);
|
|
expect(out1).toEqual(`@import url("/foo.css;900;800\\"");`);
|
|
|
|
const out2 = escapeImportStatement({
|
|
cssText: `@import url("/foo.css;900;800"") supports(display: flex);`,
|
|
href: '/foo.css;900;800"',
|
|
media: {
|
|
length: 0,
|
|
},
|
|
layerName: null,
|
|
supportsText: 'display: flex',
|
|
} as unknown as CSSImportRule);
|
|
expect(out2).toEqual(
|
|
`@import url("/foo.css;900;800\\"") supports(display: flex);`,
|
|
);
|
|
|
|
const out3 = escapeImportStatement({
|
|
cssText: `@import url("/foo.css;900;800"");`,
|
|
href: '/foo.css;900;800"',
|
|
media: {
|
|
length: 1,
|
|
mediaText: 'print, screen',
|
|
},
|
|
layerName: null,
|
|
supportsText: null,
|
|
} as unknown as CSSImportRule);
|
|
expect(out3).toEqual(`@import url("/foo.css;900;800\\"") print, screen;`);
|
|
|
|
const out4 = escapeImportStatement({
|
|
cssText: `@import url("/foo.css;900;800"") layer(layer-1);`,
|
|
href: '/foo.css;900;800"',
|
|
media: {
|
|
length: 0,
|
|
},
|
|
layerName: 'layer-1',
|
|
supportsText: null,
|
|
} as unknown as CSSImportRule);
|
|
expect(out4).toEqual(`@import url("/foo.css;900;800\\"") layer(layer-1);`);
|
|
|
|
const out5 = escapeImportStatement({
|
|
cssText: `@import url("/foo.css;900;800"") layer;`,
|
|
href: '/foo.css;900;800"',
|
|
media: {
|
|
length: 0,
|
|
},
|
|
layerName: '',
|
|
supportsText: null,
|
|
} as unknown as CSSImportRule);
|
|
expect(out5).toEqual(`@import url("/foo.css;900;800\\"") layer;`);
|
|
});
|
|
});
|