Skip to content

Commit

Permalink
Merge branch 'master' into vue-2
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinigami92 committed Mar 23, 2021
2 parents 81cf565 + e10a976 commit 73d39cf
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 261 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
12 changes: 11 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"googletagmanager",
"gtm",
"jsdoc",
"junit",
"noninteraction",
"nullish",
"overridable",
Expand All @@ -102,5 +103,14 @@
"jsdoc": {
"mode": "typescript"
}
}
},
"overrides": [
{
"files": ["tests/**/*.ts"],
"rules": {
"@typescript-eslint/unbound-method": "off",
"jsdoc/require-jsdoc": "off"
}
}
]
}
15 changes: 8 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [10.x, 12.x, 14.x, 15.x]
node: [12.x, 14.x, 15.x]
fail-fast: false

steps:
Expand All @@ -36,13 +36,13 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Check outdated dependencies
if: github.ref == 'refs/heads/master'
run: yarn outdated

- name: Lint
if: matrix.os == 'ubuntu-latest' && matrix.node == '14.x'
run: yarn lint

- name: Build
run: yarn build

- name: Test
run: yarn jest --ci --silent --reporters=default --reporters=jest-junit

Expand All @@ -59,5 +59,6 @@ jobs:
- name: Audit peerDependencies
run: yarn audit --groups peerDependencies

- name: Build
run: yarn build
- name: Check outdated dependencies
if: github.ref == 'refs/heads/master'
run: yarn outdated
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# Next

[diff](https://github.com/mib200/vue-gtm/compare/3.4.1...master)
[diff](https://github.com/mib200/vue-gtm/compare/3.5.0...master)

# 3.5.0

[diff](https://github.com/mib200/vue-gtm/compare/3.4.1...3.5.0)

- Add `nonce` for CSP support ([#116])

**Vue 3 only**

- Handle optional dependency of `vue-router` ([#122])

[#116]: https://github.com/mib200/vue-gtm/issues/116
[#122]: https://github.com/mib200/vue-gtm/issues/122

# 3.4.1

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ app.use(
},
defer: false, // Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). Defaults to false, so the script is loaded `async` by default
compatibility: false, // Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async`
nonce: "2726c7f26c", // Will add `nonce` to the script tag
enabled: true, // defaults to true. Plugin can be disabled by setting this to false for Ex: enabled: !!GDPR_Cookie (optional)
debug: true, // Whether or not display console logs debugs (optional)
loadScript: true, // Whether or not to load the GTM Script (Helpful if you are including GTM manually, but need the dataLayer functionality in your components) (optional)
Expand Down
20 changes: 9 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-gtm",
"version": "3.4.1-vue2",
"version": "3.5.0-vue2",
"description": "Google Tag Manager implementation in Vue application",
"main": "dist/index.js",
"author": {
Expand All @@ -20,9 +20,7 @@
"clean": "rm -Rf dist yarn.lock node_modules",
"build": "tsc",
"format": "prettier --write .",
"lint": "yarn lint:src",
"lint:src": "eslint --ext .ts src",
"lint:test": "eslint --ext .test.ts tests",
"lint": "eslint .",
"test": "jest",
"prepublishOnly": "yarn clean && yarn install --cache-folder .yarn && yarn build"
},
Expand Down Expand Up @@ -61,20 +59,20 @@
"url-search-params-polyfill": "^8.1.0"
},
"devDependencies": {
"@types/jest": "~26.0.20",
"@typescript-eslint/eslint-plugin": "~4.16.1",
"@typescript-eslint/parser": "~4.16.1",
"eslint": "~7.21.0",
"@types/jest": "~26.0.21",
"@typescript-eslint/eslint-plugin": "~4.19.0",
"@typescript-eslint/parser": "~4.19.0",
"eslint": "~7.22.0",
"eslint-config-prettier": "~8.1.0",
"eslint-plugin-jsdoc": "~32.2.0",
"eslint-plugin-jsdoc": "~32.3.0",
"eslint-plugin-prettier": "~3.3.1",
"eslint-plugin-spellcheck": "~0.0.17",
"jest": "~26.6.3",
"jest-junit": "~12.0.0",
"prettier": "2.2.1",
"prettier-plugin-organize-imports": "~1.1.1",
"ts-jest": "~26.5.2",
"typescript": "~4.2.2",
"ts-jest": "~26.5.4",
"typescript": "~4.2.3",
"vue": "^2.6.12",
"vue-router": "^3.5.1"
},
Expand Down
6 changes: 6 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ export interface VueGtmUseOptions {
* @default false
*/
compatibility?: boolean;
/**
* Will add `nonce` to the script tag.
*
* @see [Using Google Tag Manager with a Content Security Policy](https://developers.google.com/tag-manager/web/csp)
*/
nonce?: string;
/**
* Plugin can be disabled by setting this to `false`.
*
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function install(Vue: typeof _Vue, options: VueGtmUseOptions = { id: "" }): void
*/
function initVueRouterGuard(
Vue: typeof _Vue,
vueRouter: VueGtmUseOptions["vueRouter"],
vueRouter: Exclude<VueGtmUseOptions["vueRouter"], undefined>,
ignoredViews: VueGtmUseOptions["ignoredViews"] = [],
trackOnNextTick: VueGtmUseOptions["trackOnNextTick"]
): void {
Expand Down
6 changes: 5 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { VueGtmUseOptions } from "./config";
*/
export function loadScript(
id: string,
config: Pick<VueGtmUseOptions, "defer" | "compatibility" | "queryParams"> = {}
config: Pick<VueGtmUseOptions, "defer" | "compatibility" | "nonce" | "queryParams"> = {}
): void {
const doc: Document = document;
const script: HTMLScriptElement = doc.createElement("script");
Expand All @@ -29,6 +29,10 @@ export function loadScript(
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
script.defer = Boolean(config.defer || config.compatibility);

if (config.nonce) {
script.nonce = config.nonce;
}

const queryString: URLSearchParams = new URLSearchParams({
id,
...(config.queryParams ?? {}),
Expand Down
5 changes: 3 additions & 2 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import Vue from "vue";
import { CombinedVueInstance } from "vue/types/vue";
import VueGtm, { useGtm } from "../src/index";
import { appendAppDivToBody, cleanUpDataLayer, createAppWithComponent } from "./vue-helper";
import { appendAppDivToBody, createAppWithComponent, resetDataLayer, resetHtml } from "./vue-helper";

describe("Default", () => {
afterEach(() => {
cleanUpDataLayer();
resetHtml();
resetDataLayer();
});

test("should expose Vue plugin", () => {
Expand Down
5 changes: 4 additions & 1 deletion tests/vue-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ export function createAppWithComponent() {
return { app, component: appComponent };
}

export function cleanUpDataLayer(): void {
export function resetHtml(): void {
const html: HTMLHtmlElement = document.getElementsByTagName("html")[0] as HTMLHtmlElement;
html.innerHTML = "";
}

export function resetDataLayer(): void {
delete window["dataLayer"];
}
81 changes: 71 additions & 10 deletions tests/vue-use.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { CombinedVueInstance, ExtendedVue } from "vue/types/vue";
import VueGtm from "../src/index";
import type { DataLayerObject } from "../src/plugin";
import VueGtmPlugin from "../src/plugin";
import { appendAppDivToBody, cleanUpDataLayer, createAppWithComponent } from "./vue-helper";
import { appendAppDivToBody, createAppWithComponent, resetDataLayer, resetHtml } from "./vue-helper";

// TODO: Find out why Vue in vue-2 is undefined

// Skip for now
describe.skip("Vue.use", () => {
afterEach(() => {
cleanUpDataLayer();
resetHtml();
resetDataLayer();
});

test("should append google tag manager script to DOM", () => {
Expand Down Expand Up @@ -126,6 +127,74 @@ describe.skip("Vue.use", () => {
expect(document.scripts.item(0)?.src).toBe("https://www.googletagmanager.com/gtm.js?id=GTM-DEMO");
});

describe("Check src.nonce", () => {
afterEach(() => {
resetHtml();
});

test("should not set src.nonce by default", () => {
appendAppDivToBody();
const app: ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>> = Vue.extend({
name: "App",
render(createElement) {
return createElement("div");
},
});

Vue.use(VueGtm, { id: "GTM-DEMO" });

new Vue({
render: (h) => h(app),
}).$mount("#app");

expect(document.scripts.length).toBe(1);
expect(document.scripts.item(0)).toBeDefined();
expect(document.scripts.item(0)?.nonce).toBe("");
});

test("should set src.nonce if configured", () => {
appendAppDivToBody();
const app: ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>> = Vue.extend({
name: "App",
render(createElement) {
return createElement("div");
},
});

const nonce: string = "2726c7f26c";

Vue.use(VueGtm, { id: "GTM-DEMO", nonce });

new Vue({
render: (h) => h(app),
}).$mount("#app");

expect(document.scripts.length).toBe(1);
expect(document.scripts.item(0)).toBeDefined();
expect(document.scripts.item(0)?.nonce).toBe(nonce);
});

test("should set src.nonce to empty", () => {
appendAppDivToBody();
const app: ExtendedVue<Vue, unknown, unknown, unknown, Record<never, any>> = Vue.extend({
name: "App",
render(createElement) {
return createElement("div");
},
});

Vue.use(VueGtm, { id: "GTM-DEMO", nonce: "" });

new Vue({
render: (h) => h(app),
}).$mount("#app");

expect(document.scripts.length).toBe(1);
expect(document.scripts.item(0)).toBeDefined();
expect(document.scripts.item(0)?.nonce).toBe("");
});
});

test("should expose enable and enabled function", () => {
appendAppDivToBody();
const { app } = createAppWithComponent();
Expand All @@ -139,9 +208,7 @@ describe.skip("Vue.use", () => {

const gtmPlugin: VueGtmPlugin = vue.$gtm;

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.enable).toBeInstanceOf(Function);
// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.enabled).toBeInstanceOf(Function);

expect(gtmPlugin.enabled()).toBeFalsy();
Expand Down Expand Up @@ -169,9 +236,7 @@ describe.skip("Vue.use", () => {

const gtmPlugin: VueGtmPlugin = vue.$gtm;

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.debug).toBeInstanceOf(Function);
// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.debugEnabled).toBeInstanceOf(Function);

expect(gtmPlugin.debugEnabled()).toBeFalsy();
Expand All @@ -196,9 +261,7 @@ describe.skip("Vue.use", () => {

const gtmPlugin: VueGtmPlugin = vue.$gtm;

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.dataLayer).toBeInstanceOf(Function);

expect(gtmPlugin.dataLayer()).toEqual(window["dataLayer"]);

gtmPlugin.enable(false);
Expand Down Expand Up @@ -248,7 +311,6 @@ describe.skip("Vue.use", () => {

const gtmPlugin: VueGtmPlugin = vue.$gtm;

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.trackView).toBeInstanceOf(Function);

gtmPlugin.trackView("ScreenName", "Path");
Expand Down Expand Up @@ -281,7 +343,6 @@ describe.skip("Vue.use", () => {

const gtmPlugin: VueGtmPlugin = vue.$gtm;

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(gtmPlugin.trackEvent).toBeInstanceOf(Function);

gtmPlugin.trackEvent();
Expand Down
Loading

0 comments on commit 73d39cf

Please sign in to comment.