Skip to content
This repository has been archived by the owner on May 29, 2023. It is now read-only.

Commit

Permalink
Merge 8ec86c4 into a71b642
Browse files Browse the repository at this point in the history
  • Loading branch information
waterplea committed Mar 5, 2021
2 parents a71b642 + 8ec86c4 commit 8171f06
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 121 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ will provide the same functionality on the server side as you have in browser. I
you will get type-safe mocks 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.

> **IMPORTANT:** This library relies on **_Node.js_ v10** and above on your server side
## Mocks

Add following line to your `server.ts` to mock native classes used in other @ng-web-apis packages:
Expand All @@ -32,7 +34,19 @@ import '@ng-web-apis/universal/mocks';

## Tokens

- `WINDOW` — no need to provide fallback, Angular Universal handles it
You can provide tokens from this package into your `app.server.module.ts`
to have type safe mocks for global objects on server side:

```ts
@NgModule({
imports: [AppBrowserModule, ServerModule],
bootstrap: [AppComponent],
providers: [UNIVERSAL_WINDOW],
})
export class AppServerModule {}
```

- `WINDOW` — add `UNIVERSAL_WINDOW` to provide type-safe mock object, effectively mocking all `navigator` related entities
- `NAVIGATOR` — add `UNIVERSAL_NAVIGATOR` to provide type-safe mock object, effectively mocking all `navigator` related entities
- `NETWORK_INFORMATION` — no need to do anything
- `USER_AGENT` — see _special cases_ below
Expand Down
5 changes: 5 additions & 0 deletions projects/universal/src/classes/blob-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class BlobMock implements Blob {
size = 0;
type = '';
slice = () => this;
}
4 changes: 2 additions & 2 deletions projects/universal/src/constants/universal-location.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {FactoryProvider} from '@angular/core';
import {USER_AGENT} from '@ng-web-apis/common';
import {LOCATION} from '@ng-web-apis/common';
import {SSR_LOCATION} from '../tokens/ssr-location';
import {identity} from '../utils/functions';

export const UNIVERSAL_LOCATION: FactoryProvider = {
provide: USER_AGENT,
provide: LOCATION,
deps: [SSR_LOCATION],
useFactory: identity,
};
196 changes: 98 additions & 98 deletions projects/universal/src/constants/universal-navigator.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import {FactoryProvider, Optional} from '@angular/core';
import {NAVIGATOR} from '@ng-web-apis/common';
import {SSR_USER_AGENT} from '../tokens/ssr-user-agent';
import {EVENT_TARGET} from '../utils/event-target';
import {
alwaysFalse,
alwaysRejected,
alwaysZero,
empty,
emptyArray,
emptyFunction,
emptyObject,
} from '../utils/functions';

const EVENT_TARGET: EventTarget = {
addEventListener: empty,
dispatchEvent: alwaysFalse,
removeEventListener: empty,
};

const PLUGIN = new (class extends Array<MimeType> implements Plugin {
readonly description = '';
readonly filename = '';
Expand Down Expand Up @@ -55,100 +50,105 @@ interface NavigatorLike extends Navigator {
[key: string]: any;
}

export const NAVIGATOR_MOCK: NavigatorLike = {
appCodeName: '',
appName: '',
appVersion: '',
platform: '',
product: '',
productSub: '',
userAgent: '',
vendor: '',
vendorSub: '',

onLine: false,

confirmSiteSpecificTrackingException: alwaysFalse,
confirmWebWideTrackingException: alwaysFalse,
removeSiteSpecificTrackingException: emptyFunction,
removeWebWideTrackingException: emptyFunction,
storeSiteSpecificTrackingException: emptyFunction,
storeWebWideTrackingException: emptyFunction,

msSaveBlob: alwaysFalse,
msSaveOrOpenBlob: alwaysFalse,

sendBeacon: alwaysFalse,

hardwareConcurrency: 0,

getDisplayMedia: alwaysRejected,

language: '',
languages: [],

storage: {
estimate: alwaysRejected,
persist: alwaysRejected,
persisted: alwaysRejected,
},

activeVRDisplays: [],
authentication: {
getAssertion: alwaysRejected,
makeCredential: alwaysRejected,
},
clipboard: {
...EVENT_TARGET,
readText: alwaysRejected,
writeText: alwaysRejected,
},
cookieEnabled: false,
doNotTrack: null,
gamepadInputEmulation: 'keyboard',
geolocation: {
clearWatch: emptyFunction,
getCurrentPosition: emptyFunction,
watchPosition: alwaysZero,
},
maxTouchPoints: 0,
mediaDevices: {
...EVENT_TARGET,
ondevicechange: null,
enumerateDevices: alwaysRejected,
getSupportedConstraints: emptyObject,
getUserMedia: alwaysRejected,
},
mimeTypes: MIME_TYPES,
msManipulationViewsEnabled: false,
msMaxTouchPoints: 0,
msPointerEnabled: false,
permissions: {
query: alwaysRejected,
},
plugins: MIME_TYPES,
pointerEnabled: false,
serviceWorker: {
...EVENT_TARGET,
controller: null,
oncontrollerchange: null,
onmessage: null,
onmessageerror: null,
ready: alwaysRejected(),
getRegistration: alwaysRejected,
getRegistrations: alwaysRejected,
register: alwaysRejected,
startMessages: emptyFunction,
},
webdriver: false,
getGamepads: emptyArray,
getUserMedia: emptyFunction,
getVRDisplays: alwaysRejected,
javaEnabled: alwaysFalse,
msLaunchUri: emptyFunction,
requestMediaKeySystemAccess: alwaysRejected,
vibrate: alwaysFalse,
};

export function navigatorFactory(userAgent: string | null): NavigatorLike {
return {
appCodeName: '',
appName: '',
appVersion: '',
platform: '',
product: '',
productSub: '',
...NAVIGATOR_MOCK,
userAgent: userAgent || '',
vendor: '',
vendorSub: '',

onLine: false,

confirmSiteSpecificTrackingException: alwaysFalse,
confirmWebWideTrackingException: alwaysFalse,
removeSiteSpecificTrackingException: empty,
removeWebWideTrackingException: empty,
storeSiteSpecificTrackingException: empty,
storeWebWideTrackingException: empty,

msSaveBlob: alwaysFalse,
msSaveOrOpenBlob: alwaysFalse,

sendBeacon: alwaysFalse,

hardwareConcurrency: 0,

getDisplayMedia: alwaysRejected,

language: '',
languages: [],

storage: {
estimate: alwaysRejected,
persist: alwaysRejected,
persisted: alwaysRejected,
},

activeVRDisplays: [],
authentication: {
getAssertion: alwaysRejected,
makeCredential: alwaysRejected,
},
clipboard: {
...EVENT_TARGET,
readText: alwaysRejected,
writeText: alwaysRejected,
},
cookieEnabled: false,
doNotTrack: null,
gamepadInputEmulation: 'keyboard',
geolocation: {
clearWatch: empty,
getCurrentPosition: empty,
watchPosition: alwaysZero,
},
maxTouchPoints: 0,
mediaDevices: {
...EVENT_TARGET,
ondevicechange: null,
enumerateDevices: alwaysRejected,
getSupportedConstraints: emptyObject,
getUserMedia: alwaysRejected,
},
mimeTypes: MIME_TYPES,
msManipulationViewsEnabled: false,
msMaxTouchPoints: 0,
msPointerEnabled: false,
permissions: {
query: alwaysRejected,
},
plugins: MIME_TYPES,
pointerEnabled: false,
serviceWorker: {
...EVENT_TARGET,
controller: null,
oncontrollerchange: null,
onmessage: null,
onmessageerror: null,
ready: alwaysRejected(),
getRegistration: alwaysRejected,
getRegistrations: alwaysRejected,
register: alwaysRejected,
startMessages: empty,
},
webdriver: false,
getGamepads: emptyArray,
getUserMedia: empty,
getVRDisplays: alwaysRejected,
javaEnabled: alwaysFalse,
msLaunchUri: empty,
requestMediaKeySystemAccess: alwaysRejected,
vibrate: alwaysFalse,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {UNIVERSAL_PERFORMANCE} from './universal-performance';
import {UNIVERSAL_SESSION_STORAGE} from './universal-session-storage';
import {UNIVERSAL_SPEECH_SYNTHESIS} from './universal-speech-synthesis';
import {UNIVERSAL_USER_AGENT} from './universal-user-agent';
import {UNIVERSAL_WINDOW} from './universal-window';

export const UNIVERSAL_PROVIDERS: Provider[] = [
UNIVERSAL_ANIMATION_FRAME,
Expand All @@ -17,6 +18,7 @@ export const UNIVERSAL_PROVIDERS: Provider[] = [
UNIVERSAL_PERFORMANCE,
UNIVERSAL_SPEECH_SYNTHESIS,
UNIVERSAL_USER_AGENT,
UNIVERSAL_WINDOW,
];

/** @deprecated use {@link UNIVERSAL_PROVIDERS} */
Expand Down
20 changes: 10 additions & 10 deletions projects/universal/src/constants/universal-speech-synthesis.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import {ValueProvider} from '@angular/core';
import {SPEECH_SYNTHESIS} from '@ng-web-apis/common';
import {alwaysFalse, empty, emptyArray} from '../utils/functions';
import {alwaysFalse, emptyArray, emptyFunction} from '../utils/functions';

const MOCK: SpeechSynthesis = {
export const SPEECH_SYNTHESIS_MOCK: SpeechSynthesis = {
paused: false,
pending: false,
speaking: false,
onvoiceschanged: empty,
addEventListener: empty,
removeEventListener: empty,
onvoiceschanged: emptyFunction,
addEventListener: emptyFunction,
removeEventListener: emptyFunction,
dispatchEvent: alwaysFalse,
cancel: empty,
pause: empty,
resume: empty,
speak: empty,
cancel: emptyFunction,
pause: emptyFunction,
resume: emptyFunction,
speak: emptyFunction,
getVoices: emptyArray,
};

export const UNIVERSAL_SPEECH_SYNTHESIS: ValueProvider = {
provide: SPEECH_SYNTHESIS,
useValue: MOCK,
useValue: SPEECH_SYNTHESIS_MOCK,
};

0 comments on commit 8171f06

Please sign in to comment.