Skip to content

Commit

Permalink
feat: provide testing implementation
Browse files Browse the repository at this point in the history
You can now easily test your components depending on Matomo features by using `provideMatomoTesting()` in `TestBed`.

Cherry-picked from ef5d358
  • Loading branch information
EmmanuelRoux committed Mar 31, 2024
1 parent 088798b commit eeb6d68
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 9 deletions.
33 changes: 24 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ easily migrate.**
* [Can I use `ngx-matomo-client` with Server-side rendering (SSR) / Angular Universal?](#can-i-use-ngx-matomo-client-with-server-side-rendering-ssr--angular-universal)
* [Can I use `ngx-matomo-client` with Tag Manager?](#can-i-use-ngx-matomo-client-with-tag-manager)
* [How to define configuration asynchronously? (HTTP fetch...)](#how-to-define-configuration-asynchronously-http-fetch)
* [How can I test my components which uses `MatomoTracker` or other Matomo features?](#how-can-i-test-my-components-which-uses-matomotracker-or-other-matomo-features)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
- [Launch demo app](#launch-demo-app)
Expand Down Expand Up @@ -184,7 +185,8 @@ import {
NgxMatomoRouterModule,
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand All @@ -205,7 +207,8 @@ import {
),
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand Down Expand Up @@ -299,7 +302,8 @@ import {
}),
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand All @@ -323,7 +327,8 @@ import {
),
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand Down Expand Up @@ -400,7 +405,8 @@ import {
}),
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand All @@ -426,7 +432,8 @@ import {
),
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand Down Expand Up @@ -806,7 +813,8 @@ import {
}
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand All @@ -821,12 +829,13 @@ import {
@NgModule({
providers: [
provideMatomo(
{ ... }, // Configuration
{...}, // Configuration
withScriptFactory(myScriptFactory),
)
],
})
export class AppModule {}
export class AppModule {
}
```

</td>
Expand Down Expand Up @@ -901,6 +910,12 @@ This is required because some properties require to be set **before** any other
example, `requireConsent` must be set before any other tracking call and `trackAppInitialLoad` should be set before
any navigation occurs._

### How can I test my components which uses `MatomoTracker` or other Matomo features?

Matomo can be easily mocked and tested by declaring either `provideMatomoTesting()` providers or `MatomoTestingModule` in `TestBed`.

All these symbols can be imported from `ngx-matomo-client/testing`.

## Roadmap

[See roadmap here](docs/roadmap.md)
Expand Down
1 change: 1 addition & 0 deletions projects/ngx-matomo-client/core/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export {
MatomoECommerceItemView,
MatomoECommerceCategoryView,
PagePerformanceTimings,
MatomoInstance,
} from './tracker/matomo-tracker.service';
export { MatomoInitializerService } from './tracker/matomo-initializer.service';
export {
Expand Down
1 change: 1 addition & 0 deletions projects/ngx-matomo-client/testing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public-api';
110 changes: 110 additions & 0 deletions projects/ngx-matomo-client/testing/matomo-testing-instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { MatomoECommerceItem, MatomoInstance } from 'ngx-matomo-client/core';

/**
* No-op implementation of {@link MatomoInstance}
*/
export class MatomoTestingInstance implements MatomoInstance {
areCookiesEnabled(): boolean {
return false;
}

getAttributionCampaignKeyword(): string {
return '';
}

getAttributionCampaignName(): string {
return '';
}

getAttributionInfo(): string[] {
return [];
}

getAttributionReferrerTimestamp(): string {
return '';
}

getAttributionReferrerUrl(): string {
return '';
}

getCrossDomainLinkingUrlParameter(): string {
return '';
}

getCurrentUrl(): string {
return '';
}

getCustomDimension(customDimensionId: number): string {
return '';
}

getCustomPagePerformanceTiming(): string {
return '';
}

getCustomVariable(index: number, scope: string): string {
return '';
}

getEcommerceItems(): MatomoECommerceItem[] {
return [];
}

getExcludedReferrers(): string[] {
return [];
}

getLinkTrackingTimer(): number {
return 0;
}

getMatomoUrl(): string {
return '';
}

getPageViewId(): string {
return '';
}

getPiwikUrl(): string {
return '';
}

getRememberedConsent(): number | string {
return '';
}

getRememberedCookieConsent(): number | string {
return '';
}

getUserId(): string {
return '';
}

getVisitorId(): string {
return '';
}

getVisitorInfo(): unknown[] {
return [];
}

hasCookies(): boolean {
return false;
}

hasRememberedConsent(): boolean {
return false;
}

isConsentRequired(): boolean {
return false;
}

isUserOptedOut(): boolean {
return false;
}
}
49 changes: 49 additions & 0 deletions projects/ngx-matomo-client/testing/matomo-testing-tracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { MatomoInstance, MatomoTracker } from 'ngx-matomo-client/core';
import { MatomoTestingInstance } from './matomo-testing-instance';

/**
* No-op implementation of {@link MatomoTracker}
*
* All commands are memoized and can later be retrieved using
* {@link getAllCommands getAllCommands()} or {@link getCommand getCommand(index)}.
*
* All <i>getter</i> methods will immediately resolve to an <i>empty value</i>.
* This can be customized by setting a custom Matomo instance with {@link setMatomoInstance setMatomoInstance()}.
*/
export class MatomoTestingTracker extends MatomoTracker {
#fakeInstance: MatomoInstance = new MatomoTestingInstance();
#paq: unknown[][] = [];

/** Retrieve the current Matomo instance */
getMatomoInstance(): MatomoInstance {
return this.#fakeInstance;
}

/** Set the current matomo instance */
setMatomoInstance(instance: MatomoInstance) {
this.#fakeInstance = instance;
}

/** Retrieve all memoized commands */
getAllCommands(): unknown[][] {
return [...this.#paq];
}

/** Retrieve nth memoized command */
getCommand(index: number): unknown[] | undefined {
return this.#paq[index];
}

/** Clear all memoized commands */
reset() {
this.#paq = [];
}

protected push(command: unknown[]): void {
this.#paq.push(command);
}

protected async pushFn<T>(fn: (matomo: MatomoInstance) => T): Promise<T> {
return fn(this.#fakeInstance);
}
}
20 changes: 20 additions & 0 deletions projects/ngx-matomo-client/testing/matomo-testing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import {
MatomoOptOutFormComponent,
MatomoTrackClickDirective,
MatomoTrackerDirective,
} from 'ngx-matomo-client/core';
import { provideMatomoTesting } from './providers';

@NgModule({
imports: [MatomoTrackerDirective, MatomoTrackClickDirective, MatomoOptOutFormComponent],
exports: [MatomoTrackerDirective, MatomoTrackClickDirective, MatomoOptOutFormComponent],
})
export class MatomoTestingModule {
static forRoot(): ModuleWithProviders<MatomoTestingModule> {
return {
ngModule: MatomoTestingModule,
providers: [provideMatomoTesting()],
};
}
}
6 changes: 6 additions & 0 deletions projects/ngx-matomo-client/testing/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"lib": {
"entryFile": "public-api.ts"
}
}
45 changes: 45 additions & 0 deletions projects/ngx-matomo-client/testing/providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { EnvironmentProviders, makeEnvironmentProviders, Provider } from '@angular/core';
import {
MATOMO_CONFIGURATION,
MatomoConfiguration,
MatomoFeature,
MatomoTracker,
} from 'ngx-matomo-client/core';
import { MatomoTestingTracker } from './matomo-testing-tracker';

/**
* Set up a no-op Matomo tracker. Useful for testing scenario.
*
*
* Testing tracker is available as both {@link MatomoTracker} and {@link MatomoTestingTracker} injection tokens,
* the latter allowing to customize testing behavior (see {@link MatomoTestingTracker}).
*
* @see MatomoTestingTracker
*/
export function provideMatomoTesting(
config: Partial<MatomoConfiguration> | (() => Partial<MatomoConfiguration>) = {},
..._ignored: MatomoFeature[]
): EnvironmentProviders {
const providers: Provider[] = [
MatomoTestingTracker,
{
provide: MatomoTracker,
useExisting: MatomoTestingTracker,
},
];

// Allow to provide a configuration, because it can be useful for users depending on `MATOMO_CONFIGURATION` in their code.
if (typeof config === 'function') {
providers.push({
provide: MATOMO_CONFIGURATION,
useFactory: config,
});
} else {
providers.push({
provide: MATOMO_CONFIGURATION,
useValue: config,
});
}

return makeEnvironmentProviders(providers);
}
4 changes: 4 additions & 0 deletions projects/ngx-matomo-client/testing/public-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { provideMatomoTesting } from './providers';
export { MatomoTestingModule } from './matomo-testing.module';
export { MatomoTestingTracker } from './matomo-testing-tracker';
export { MatomoTestingInstance } from './matomo-testing-instance';

0 comments on commit eeb6d68

Please sign in to comment.