Skip to content

Commit

Permalink
feat(ng-dev): ComponentContext no longer clears styles between test…
Browse files Browse the repository at this point in the history
…s that were added by anyone other than angular. (This is desirable when using e.g. Ionic or Fontawesome, which expect styles to persist.)

Closes #34.
  • Loading branch information
ersimont committed Jul 14, 2021
1 parent 2ff1d2c commit b42af81
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 18 deletions.
58 changes: 46 additions & 12 deletions projects/ng-dev/src/lib/component-context/component-context.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,6 @@ describe('ComponentContext', () => {
});
});

it('trims leftover styles', () => {
const ctx = new ComponentContext(TestComponent);
let style: HTMLStyleElement;
ctx.run(() => {
style = document.createElement('style');
document.head.append(style);
});
ctx.run(() => {
expect(style.parentElement).toBeNull();
});
});

it('triggers ngOnChanges', () => {
const ctx = new ComponentContext(ChangeDetectingComponent);
ctx.run(() => {
Expand Down Expand Up @@ -232,6 +220,52 @@ describe('ComponentContext', () => {
// No error: "1 periodic timer(s) still in the queue."
.not.toThrowError();
});

describe('trimming leftover component styles', () => {
@Component({
selector: 'app-styler',
template: "I'm cool",
styles: [
`
:host {
height: 20px;
background: lightblue;
}
`,
],
})
class StyledComponent {}

function getStyles(): Array<string | null> {
return Array.from(document.querySelectorAll('style')).map(
(style) => style.textContent,
);
}

let startingStyleCount: number;
beforeAll(() => {
startingStyleCount = getStyles().length;
});

// Our component adds 1 style, and we manually add 1 more. So in the test we should see only one copy of the component style, and one OR BOTH of our dynamicly added style (depending on whether this is the first or second run of the test).
for (let i = 0; i < 2; ++i) {
it('trims (only) leftover styles from angular components', () => {
const ctx = new ComponentContext(StyledComponent);
ctx.run(() => {
const style = document.createElement('style');
style.textContent = 'dynamic style';
document.head.append(style);

const styles = getStyles();
const numDynamic = styles.filter(
(style) => style === 'dynamic style',
).length;
expect(numDynamic === 1 || numDynamic === 2).toBe(true);
expect(styles.length - numDynamic).toBe(startingStyleCount + 1);
});
});
}
});
});
});

Expand Down
17 changes: 11 additions & 6 deletions projects/ng-dev/src/lib/component-context/component-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import {
TestBed,
TestModuleMetadata,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { By, ɵDomSharedStylesHost } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { keys } from '@s-libs/micro-dash';
import { trimLeftoverStyles } from '../trim-leftover-styles';
import { extendMetadata } from '../angular-context/angular-context';
import { AngularContext } from '../angular-context/angular-context';
import {
AngularContext,
extendMetadata,
} from '../angular-context/angular-context';
import {
createDynamicWrapper,
WrapperComponent,
} from './create-dynamic-wrapper';

// This fixes https://github.com/angular/angular/issues/31834. We are using it instead of `trimLeftoverStyles()` so that extra styles added by e.g. Ionic or Fontawesome are preserved. This should be temporary, with the real fix coming from Angular itself with https://github.com/angular/angular/pull/42566.
let styleHostToDestroy: ɵDomSharedStylesHost | undefined;

/**
* Provides the foundation for an opinionated pattern for component tests.
*
Expand All @@ -24,7 +28,7 @@ import {
* - Wraps your component in a dynamically created parent that you can easily style however you like.
* - Lets you use {@link https://material.angular.io/cdk/test-harnesses/overview|component harnesses} in the `fakeAsync` zone, which is normally a challenge.
* - Automatically disables animations.
* - Automatically integrates {@link trimLeftoverStyles} to speed up your test suite.
* - Automatically removes component styles from previous tests to speed up your test suite (works around https://github.com/angular/angular/issues/31834).
*
* A very simple example:
* ```ts
Expand Down Expand Up @@ -230,7 +234,7 @@ export class ComponentContext<T> extends AngularContext {
* Constructs and initializes your component. Called during `run()` before it executes the rest of your test. Runs in the same `fakeAsync` zone as the rest of your test.
*/
protected init(): void {
trimLeftoverStyles();
styleHostToDestroy?.ngOnDestroy();
super.init();
this.fixture = TestBed.createComponent(this.wrapperType);

Expand All @@ -249,6 +253,7 @@ export class ComponentContext<T> extends AngularContext {
*/
protected cleanUp(): void {
this.fixture.destroy();
styleHostToDestroy = this.inject(ɵDomSharedStylesHost);
super.cleanUp();
}

Expand Down

0 comments on commit b42af81

Please sign in to comment.