Skip to content

Commit

Permalink
feat(universal): bundle mocks with the related libs and remove global…
Browse files Browse the repository at this point in the history
… `mocks.js` (#350)
  • Loading branch information
waterplea authored Dec 15, 2023
1 parent 83fd5c7 commit 65d6b87
Show file tree
Hide file tree
Showing 15 changed files with 51 additions and 137 deletions.
2 changes: 1 addition & 1 deletion apps/demo/server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import '@ng-web-apis/universal/mocks';
import '@ng-web-apis/audio/mocks';
import 'zone.js/node';

import {APP_BASE_HREF} from '@angular/common';
Expand Down
10 changes: 7 additions & 3 deletions libs/audio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,13 @@ not support it

## Angular Universal

If you want to use this package with SSR, you need to mock native Web Audio API classes on the server. You can use our
Universal package for this, see
[this example](https://github.com/taiga-family/ng-web-apis/tree/main/libs/universal#mocks).
If you want to use this package with SSR, you need to mock native Web Audio API classes on the server:

```ts
import '@ng-web-apis/audio/mocks';
```

> It is recommended to keep the import statement at the top of your `server.ts` or `main.server.ts` file.
## Demo

Expand Down
20 changes: 0 additions & 20 deletions libs/universal/mocks.js → libs/audio/mocks.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
(function () {
'use strict';

// Mutation Observer API
global.MutationObserver = class {
observe() {}
disconnect() {}
takeRecords() {
return [];
}
};

// Intersection Observer API
global.IntersectionObserver = class {
observe() {}
unobserve() {}
disconnect() {}
takeRecords() {
return [];
}
};

// Web Audio API
global.AudioContext = class {};
global.OfflineAudioContext = class {};
global.AudioBufferSourceNode = class {};
Expand Down
13 changes: 0 additions & 13 deletions libs/intersection-observer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,6 @@ npm i @ng-web-apis/intersection-observer
> **NOTE:** Keep in mind these are used one time in constructor so you cannot use binding, only strings. Pass comma
> separated numbers to set an array of thresholds.
### Usage with Jest

DOM environment provided by Jest does not emulate IntersectionObserver API and need to be mocked. You can add the
following line to your `setup.ts`:

```ts
// setup.ts
import '@ng-web-apis/universal/mocks';
```

to use mocks from [@ng-web-apis/universal](https://github.com/taiga-family/ng-web-apis/tree/main/libs/universal#mocks)
package.

## Examples

Observing multiple elements intersecting with viewport using single observer
Expand Down
14 changes: 14 additions & 0 deletions libs/intersection-observer/src/classes/safe-observer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const SafeObserver =
typeof IntersectionObserver !== `undefined`
? IntersectionObserver
: class implements IntersectionObserver {
readonly root = null;
readonly rootMargin = ``;
readonly thresholds = [];
observe(): void {}
unobserve(): void {}
disconnect(): void {}
takeRecords(): IntersectionObserverEntry[] {
return [];
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Optional,
} from '@angular/core';

import {SafeObserver} from '../classes/safe-observer';
import {INTERSECTION_ROOT} from '../tokens/intersection-root';
import {rootMarginFactory} from '../utils/root-margin-factory';
import {thresholdFactory} from '../utils/threshold-factory';
Expand All @@ -17,10 +18,7 @@ import {thresholdFactory} from '../utils/threshold-factory';
selector: '[waIntersectionObserver]',
exportAs: 'IntersectionObserver',
})
export class IntersectionObserverDirective
extends IntersectionObserver
implements OnDestroy
{
export class IntersectionObserverDirective extends SafeObserver implements OnDestroy {
private readonly callbacks = new Map<Element, IntersectionObserverCallback>();

constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
import {ElementRef, Inject, Injectable, Optional} from '@angular/core';
import {Observable} from 'rxjs';
import {share} from 'rxjs/operators';

import {SafeObserver} from '../classes/safe-observer';
import {INTERSECTION_ROOT} from '../tokens/intersection-root';
import {INTERSECTION_ROOT_MARGIN} from '../tokens/intersection-root-margin';
import {INTERSECTION_THRESHOLD} from '../tokens/intersection-threshold';
import {INTERSECTION_OBSERVER_SUPPORT} from '../tokens/support';

@Injectable()
export class IntersectionObserverService extends Observable<IntersectionObserverEntry[]> {
constructor(
@Inject(ElementRef) {nativeElement}: ElementRef<Element>,
@Inject(INTERSECTION_OBSERVER_SUPPORT) support: boolean,
@Inject(INTERSECTION_ROOT_MARGIN) rootMargin: string,
@Inject(INTERSECTION_THRESHOLD) threshold: number[] | number,
@Optional() @Inject(INTERSECTION_ROOT) root: ElementRef<Element> | null,
) {
super(subscriber => {
if (!support) {
subscriber.error(`IntersectionObserver is not supported in your browser`);

return;
}

const observer = new IntersectionObserver(
const observer = new SafeObserver(
entries => {
subscriber.next(entries);
},
Expand All @@ -40,7 +32,5 @@ export class IntersectionObserverService extends Observable<IntersectionObserver
observer.disconnect();
};
});

return this.pipe(share());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ describe(`IntersectionObserverService`, () => {
{
nativeElement,
},
true,
`0px 0px 0px 0px`,
0,
{
Expand All @@ -32,25 +31,4 @@ describe(`IntersectionObserverService`, () => {
done();
});
});

it(`throws when not supported`, () => {
let error = false;
const service = new IntersectionObserverService(
{
nativeElement: document.createElement(`DIV`),
},
false,
`0px 0px 0px 0px`,
0,
null,
);

service.subscribe({
error: () => {
error = true;
},
});

expect(error).toBe(true);
});
});
10 changes: 10 additions & 0 deletions libs/mutation-observer/src/classes/safe-observer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const SafeObserver =
typeof MutationObserver !== `undefined`
? MutationObserver
: class implements MutationObserver {
observe(): void {}
disconnect(): void {}
takeRecords(): MutationRecord[] {
return [];
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Output,
} from '@angular/core';

import {SafeObserver} from '../classes/safe-observer';
import {MUTATION_OBSERVER_INIT} from '../tokens/mutation-observer-init';
import {mutationObserverInitFactory} from '../utils/mutation-observer-init-factory';

Expand All @@ -24,7 +25,7 @@ import {mutationObserverInitFactory} from '../utils/mutation-observer-init-facto
],
exportAs: 'MutationObserver',
})
export class MutationObserverDirective extends MutationObserver implements OnDestroy {
export class MutationObserverDirective extends SafeObserver implements OnDestroy {
@Output()
readonly waMutationObserver = new EventEmitter<MutationRecord[]>();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {ElementRef, Inject, Injectable} from '@angular/core';
import {Observable} from 'rxjs';

import {SafeObserver} from '../classes/safe-observer';
import {MUTATION_OBSERVER_INIT} from '../tokens/mutation-observer-init';

@Injectable()
Expand All @@ -10,7 +11,7 @@ export class MutationObserverService extends Observable<readonly MutationRecord[
@Inject(MUTATION_OBSERVER_INIT) config: MutationObserverInit,
) {
super(subscriber => {
const observer = new MutationObserver(records => {
const observer = new SafeObserver(records => {
subscriber.next(records);
});

Expand Down
8 changes: 8 additions & 0 deletions libs/resize-observer/src/classes/safe-observer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const SafeObserver =
typeof ResizeObserver !== `undefined`
? ResizeObserver
: class implements ResizeObserver {
observe(): void {}
unobserve(): void {}
disconnect(): void {}
};
22 changes: 3 additions & 19 deletions libs/resize-observer/src/services/resize-observer.service.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,23 @@
import {ElementRef, Inject, Injectable, NgZone} from '@angular/core';
import {ElementRef, Inject, Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {share} from 'rxjs/operators';

import {SafeObserver} from '../classes/safe-observer';
import {RESIZE_OPTION_BOX} from '../tokens/resize-option-box';
import {RESIZE_OBSERVER_SUPPORT} from '../tokens/support';

@Injectable()
export class ResizeObserverService extends Observable<readonly ResizeObserverEntry[]> {
constructor(
@Inject(ElementRef) {nativeElement}: ElementRef<Element>,
@Inject(NgZone) ngZone: NgZone,
@Inject(RESIZE_OBSERVER_SUPPORT) support: boolean,
@Inject(RESIZE_OPTION_BOX) box: ResizeObserverBoxOptions,
) {
let observer: ResizeObserver;

super(subscriber => {
if (!support) {
subscriber.error(`ResizeObserver is not supported in your browser`);

return;
}
const observer = new SafeObserver(entries => subscriber.next(entries));

observer = new ResizeObserver(entries => {
ngZone.run(() => {
subscriber.next(entries);
});
});
observer.observe(nativeElement, {box});

return () => {
observer.disconnect();
};
});

return this.pipe(share());
}
}
31 changes: 0 additions & 31 deletions libs/resize-observer/tests/resize-observer.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {TestBed} from '@angular/core/testing';
import {catchError} from 'rxjs/operators';

import {ResizeObserverService} from '../src/services/resize-observer.service';
import {RESIZE_OBSERVER_SUPPORT} from '../src/tokens/support';

describe(`ResizeObserver`, () => {
describe(`Resize Observer token`, () => {
Expand Down Expand Up @@ -36,34 +35,4 @@ describe(`ResizeObserver`, () => {
expect(service).toBeDefined();
});
});

describe(`throws when not supported`, () => {
it(`Throws an error if ResizeObserver is not supported`, done => {
TestBed.configureTestingModule({
providers: [
ResizeObserverService,
{
provide: ElementRef,
useValue: {
nativeElement: document.createElement(`DIV`),
},
},
{
provide: RESIZE_OBSERVER_SUPPORT,
useValue: false,
},
],
});

const service$: ResizeObserverService = TestBed.inject(ResizeObserverService);

service$.subscribe({
error: err => {
expect(err).toBe(`ResizeObserver is not supported in your browser`);

done();
},
});
});
});
});
10 changes: 0 additions & 10 deletions libs/universal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@ provide the same functionality on the server side as you have in browser. In oth
and you can at least be sure you will not have `cannot read propery of null` or `undefined is not a function` errors in
SSR.

## Mocks

Add following line to your `server.ts` to mock native classes used in other @ng-web-apis packages:

```ts
import '@ng-web-apis/universal/mocks';
```

> It is recommended to keep the import statement at the top of your `server.ts` file
## Tokens

You can provide tokens from this package into your `app.server.module.ts` to have type safe mocks for global objects on
Expand Down

0 comments on commit 65d6b87

Please sign in to comment.