Skip to content

Commit

Permalink
refactor(serializers): add option to remove comp attributes
Browse files Browse the repository at this point in the history
Closes #2578
Closes #2580
  • Loading branch information
ahnpnl committed Jul 22, 2024
1 parent 3ce21cd commit a1be63d
Show file tree
Hide file tree
Showing 7 changed files with 519 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`snapshot should work 1`] = `
exports[`FooComponent should allow generating snapshot 1`] = `
<foo
condition1={[Function Boolean]}
condition2="false"
Expand All @@ -17,7 +17,36 @@ exports[`snapshot should work 1`] = `
</foo>
`;

exports[`snapshot should work 2`] = `
exports[`FooComponent should allow generating snapshot 2`] = `
<div
id="root1"
>
<p>
Line 1
</p>
<div>
<div>
val1
</div>
</div>
</div>
`;

exports[`FooComponent should allow generating snapshot with removed component attributes with snapshot serializer option 1`] = `
<foo>
<p>
Line 1
</p><div>
<div>
val1
</div>
</div>
</foo>
`;

exports[`FooComponent should allow generating snapshot with removed component attributes with snapshot serializer option 2`] = `
<div
id="root0"
>
Expand Down
1 change: 1 addition & 0 deletions e2e/snapshot-serializers/__tests__/foo.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- SOMETHING -->
<p>Line 1</p>
<div>
<div *ngIf="condition1">
Expand Down
50 changes: 41 additions & 9 deletions e2e/snapshot-serializers/__tests__/foo.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Component, Input } from '@angular/core';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { TestBed } from '@angular/core/testing';

import serializer from '../../../build/serializers/ng-snapshot';

@Component({
selector: 'foo',
Expand All @@ -22,14 +24,44 @@ class FooComponent {
condition2 = false;
}

test('snapshot should work', waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [FooComponent],
describe('FooComponent', () => {
test('should allow generating snapshot with removed component attributes with snapshot serializer option', () => {
expect.addSnapshotSerializer({
print: (val, print, indent, options, colors) =>
serializer.print(
val,
print,
indent,
{
...options,
omitAllCompAttrs: true,
},
colors,
),
test: serializer.test,
});

TestBed.configureTestingModule({
declarations: [FooComponent],
});

const fixture = TestBed.createComponent(FooComponent);
fixture.detectChanges();

expect(fixture).toMatchSnapshot();
expect(fixture.debugElement.nativeElement).toMatchSnapshot();
});

const fixture = TestBed.createComponent(FooComponent);
fixture.detectChanges();
test('should allow generating snapshot', () => {
expect.addSnapshotSerializer(serializer);
TestBed.configureTestingModule({
declarations: [FooComponent],
});

const fixture = TestBed.createComponent(FooComponent);
fixture.detectChanges();

expect(fixture).toMatchSnapshot();
expect(fixture.debugElement.nativeElement).toMatchSnapshot();
}));
expect(fixture).toMatchSnapshot();
expect(fixture.debugElement.nativeElement).toMatchSnapshot();
});
});
54 changes: 38 additions & 16 deletions src/serializers/ng-snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,35 @@ import type { OldPlugin } from 'pretty-format';

const attributesToRemovePatterns = ['__ngContext__'];

const print: OldPlugin['print'] = (fixture, printer, indent, opts, colors) => {
let componentAttrs = '';
type PluginPrintFnArgs = Parameters<OldPlugin['print']>;

type NgSnapshotOptions = {
omitAllCompAttrs?: boolean;
};

type PluginPrintFn = (
fixture: PluginPrintFnArgs[0],
printer: PluginPrintFnArgs[1],
indent: PluginPrintFnArgs[2],
opts: PluginPrintFnArgs[3] & NgSnapshotOptions,
colors: PluginPrintFnArgs[4],
) => string;

const removeTrailingWhiteSpaces = (serializedComponent: string): string => {
return serializedComponent.replace(/\n^\s*\n/gm, '\n');
};

const print: PluginPrintFn = (fixture, printer, indent, opts, colors) => {
const { componentRef, componentInstance } = fixture as ComponentFixture<Record<string, unknown>>;
const componentDef = (componentRef.componentType as ɵComponentType<unknown>).ɵcmp as ɵDirectiveDef<unknown>;
const componentName = componentDef.selectors[0][0] as string;
const nodes = Array.from(componentRef.location.nativeElement.childNodes).map(printer).join('');
const attributes = Object.keys(componentInstance).filter((key) => !attributesToRemovePatterns.includes(key));
if (attributes.length) {
componentAttrs += attributes
let serializedComponent = '';
if (opts.omitAllCompAttrs) {
serializedComponent = '<' + componentName + '>\n' + indent(nodes) + '\n</' + componentName + '>';
} else {
const attributes = Object.keys(componentInstance).filter((key) => !attributesToRemovePatterns.includes(key));
const componentAttrs = attributes
.sort()
.map((attribute) => {
const compAttrVal = componentInstance[attribute];
Expand All @@ -28,19 +48,21 @@ const print: OldPlugin['print'] = (fixture, printer, indent, opts, colors) => {
);
})
.join('');
serializedComponent =
'<' +
componentName +
componentAttrs +
(componentAttrs.length ? '\n' : '') +
'>\n' +
indent(nodes) +
'\n</' +
componentName +
'>';
}

return (
'<' +
componentName +
componentAttrs +
(componentAttrs.length ? '\n' : '') +
'>\n' +
indent(nodes) +
'\n</' +
componentName +
'>'
).replace(/\n^\s*\n/gm, '\n');
serializedComponent = removeTrailingWhiteSpaces(serializedComponent);

return serializedComponent;
};

const test: OldPlugin['test'] = (val) => !!val && typeof val === 'object' && 'componentRef' in val;
Expand Down
7 changes: 2 additions & 5 deletions website/docs/getting-started/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default jestConfig;

```js tab
// jest.config.js
const snapshotSerializers = require('../build/serializers');
const snapshotSerializers = require('jest-preset-angular/build/serializers');

module.exports = {
moduleFileExtensions: ['ts', 'html', 'js', 'json', 'mjs'],
Expand Down Expand Up @@ -140,10 +140,7 @@ Jest runs with `jest-preset-angular` neither in browser nor through dev server.
- `"moduleFileExtensions"` – our modules are TypeScript (`ts`), HTML (`html`), JavaScript (`js`), JSON (`json`) and ESM JavaScript (`mjs`) files.
- `"moduleNameMapper"` – if you're using absolute imports here's how to tell Jest where to look for them; uses `RegExp`.
- `"resolver"` - instruct Jest how to resolve entry file based on `package.json` definitions.
- `"snapshotSerializers"` - array of serializers which will be applied to snapshot the code. Note: by default angular adds
some angular-specific attributes to the code (like `ng-reflect-*`, `ng-version="*"`, `_ngcontent-c*` etc).
This package provides serializer to remove such attributes. This makes snapshots cleaner and more human-readable.
To remove such specific attributes use `no-ng-attributes` serializer. You need to add `no-ng-attributes` serializer manually.
- `"snapshotSerializers"` - array of serializers which will be applied to snapshot the code. See more in [Snapshot testing](../guides/snapshot-testing.md)
- `"testEnvironment"` – the test environment to run on.
- `"transformIgnorePatterns"`: instruct Jest to transform any `.mjs` files which come from `node_modules`.
- `"transform"` – run every `TS`, `JS`, `MJS`, `HTML`, or `SVG` file through so called _Jest transformer_; this lets Jest understand non-JS syntax.
Loading

0 comments on commit a1be63d

Please sign in to comment.