/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/unit/test-extension-analytics.js
524 строки
17 KB
Kristofer Baxter
♻️ Remove Notice from JS and Markdown (#35717)
19 авг 2021, 21:21
Не верифицирован
19 авг 2021, 21:21
f564b7e
Код
Авторство
О чём код?
import {Services} from '#service'; import {registerElement} from '#service/custom-element-registry'; import {macroTask} from '#testing/helpers'; import {BaseElement} from '../../src/base-element'; import { CustomEventReporterBuilder, insertAnalyticsElement, useAnalyticsInSandbox, } from '../../src/extension-analytics'; import { getServiceForDoc, registerServiceBuilderForDoc, resetServiceForTesting, } from '../../src/service-helpers'; /* eslint-disable react-hooks/rules-of-hooks */ describes.realWin( 'extension-analytics', { amp: true, }, (env) => { let timer; let ampdoc; let win; describe('insertAnalyticsElement', () => { class MockInstrumentation {} beforeEach(() => { timer = Services.timerFor(env.win); ampdoc = env.ampdoc; win = env.win; }); [true, false].forEach((disableImmediate) => { it( 'should create analytics element if analytics is installed, ' + `disableImmediate ${disableImmediate}`, () => { const config = { 'requests': { 'pageview': 'https://example.test/analytics', }, 'triggers': { 'trackPageview': { 'on': 'visible', 'request': 'pageview', }, }, }; const ele = win.document.createElement('div'); win.document.body.appendChild(ele); const baseEle = new BaseElement(ele); registerServiceBuilderForDoc( ampdoc, 'amp-analytics-instrumentation', MockInstrumentation ); // Force instantiation getServiceForDoc(ampdoc, 'amp-analytics-instrumentation'); expect(baseEle.element.querySelector('amp-analytics')).to.be.null; expect( insertAnalyticsElement( baseEle.element, config, true, disableImmediate ) ).to.be.ok; return timer.promise(50).then(() => { const analyticsEle = baseEle.element.querySelector('amp-analytics'); expect(analyticsEle).to.not.be.null; expect(analyticsEle.getAttribute('sandbox')).to.equal('true'); expect(analyticsEle.getAttribute('trigger')).to.equal( disableImmediate ? '' : 'immediate' ); const script = analyticsEle.querySelector('script'); expect(script.textContent).to.jsonEqual(JSON.stringify(config)); expect(analyticsEle.CONFIG).to.jsonEqual(config); expect(analyticsEle.getAttribute('sandbox')).to.equal('true'); }); } ); }); }); describe('CustomEventReporterBuilder', () => { let builder; let parent; beforeEach(() => { parent = document.createElement('div'); builder = new CustomEventReporterBuilder(parent); }); it('track event with one request', () => { builder.track('test', 'fake.test'); expect(builder.config_).to.jsonEqual({ 'requests': { 'test-request-0': 'fake.test', }, 'triggers': { 'test': { 'on': 'test', 'request': ['test-request-0'], }, }, }); }); it('track event with multiple request', () => { builder.track('test', ['fake.test', 'fake1.test']); expect(builder.config_).to.jsonEqual({ 'requests': { 'test-request-0': 'fake.test', 'test-request-1': 'fake1.test', }, 'triggers': { 'test': { 'on': 'test', 'request': ['test-request-0', 'test-request-1'], }, }, }); }); it('track multi event', () => { builder.track('test', 'fake.test').track('test1', 'fake1.test'); expect(builder.config_).to.jsonEqual({ 'requests': { 'test-request-0': 'fake.test', 'test1-request-0': 'fake1.test', }, 'triggers': { 'test': { 'on': 'test', 'request': ['test-request-0'], }, 'test1': { 'on': 'test1', 'request': ['test1-request-0'], }, }, }); }); it('should not add already tracked event', () => { try { builder.track('test', 'fake.test').track('test', 'example.test'); } catch (e) { expect(e.message).to.equal( 'customEventReporterBuilder should not track same eventType twice' ); } }); it('should return a customEventReporter instance', () => { parent.getResourceId = () => { return 1; }; parent.signals = () => { return { whenSignal: () => { return Promise.resolve(); }, }; }; const reporter = builder.track('test', 'fake.test').build(); expect(reporter.trigger).to.exist; }); it('Should allow to specify transport config', () => { parent.getResourceId = () => { return 1; }; parent.signals = () => { return { whenSignal: () => { return Promise.resolve(); }, }; }; builder.setTransportConfig({ 'beacon': true, 'image': true, 'xhrpost': false, }); const reporter = builder.build(); expect(reporter.config_.transport).to.jsonEqual({ 'beacon': true, 'image': true, 'xhrpost': false, }); }); it('Should allow to specify extraUrlParams config', () => { parent.getResourceId = () => { return 1; }; parent.signals = () => { return { whenSignal: () => { return Promise.resolve(); }, }; }; builder.setExtraUrlParams({ 'a': 'b', }); const reporter = builder.build(); expect(reporter.config_.extraUrlParams).to.jsonEqual({ 'a': 'b', }); }); }); describe('CustomEventReporter test', () => { let builder; let parentEle; let reporter; let ampdoc; let triggerEventSpy; class MockInstrumentation { triggerEventForTarget(nodeOrDoc, eventType, opt_vars) { triggerEventSpy(nodeOrDoc, eventType, opt_vars); } } beforeEach(() => { ampdoc = env.ampdoc; triggerEventSpy = env.sandbox.spy(); resetServiceForTesting(env.win, 'amp-analytics-instrumentation'); registerServiceBuilderForDoc( ampdoc, 'amp-analytics-instrumentation', MockInstrumentation ); // Force instantiation getServiceForDoc(ampdoc, 'amp-analytics-instrumentation'); registerElement(env.win, 'amp-test', BaseElement); parentEle = env.win.document.createElement('amp-test'); parentEle.setAttribute('layout', 'nodisplay'); env.win.document.body.appendChild(parentEle); const buildPromise = parentEle.buildInternal(); builder = new CustomEventReporterBuilder(parentEle); reporter = builder.track('test', 'fake.test').build(); return buildPromise; }); it('replace eventType with new name', function* () { parentEle.layoutCallback(); yield macroTask(); const element = parentEle.querySelector('amp-analytics'); expect(element).to.not.be.null; const script = element.querySelector('script'); const id = parentEle.getResourceId(); expect(script.textContent).to.jsonEqual( JSON.stringify({ 'requests': { 'test-request-0': 'fake.test', }, 'triggers': { 'test': { 'on': `sandbox-${id}-test`, 'request': ['test-request-0'], }, }, }) ); }); it('trigger event with new name', function* () { const id = parentEle.getResourceId(); reporter.trigger('test'); yield macroTask(); expect(triggerEventSpy).to.be.calledWith( parentEle, `sandbox-${id}-test` ); }); it('should not trigger not added event', function* () { try { reporter.trigger('fake'); } catch (e) { expect(e.message).to.equal('Cannot trigger non initiated eventType'); } }); }); describe('useAnalyticsInSandbox', () => { let parentEle; let resolver; const config = { 'requests': { 'pageview': 'https://example.test/analytics', }, 'triggers': { 'trackPageview': { 'on': 'visible', 'request': 'pageview', }, }, }; const config2 = { 'requests': { 'pageview': 'https://example.test/analytics2', }, 'triggers': { 'trackPageview': { 'on': 'visible', 'request': 'pageview', }, }, }; describe('parent does NOT relayout, call in buildCallback', () => { beforeEach(() => { const promise = new Promise((resolve) => { resolver = resolve; }); class TestElement extends BaseElement { buildCallback() { useAnalyticsInSandbox(this.element, promise); } } registerElement(env.win, 'amp-test', TestElement); parentEle = env.win.document.createElement('amp-test'); parentEle.setAttribute('layout', 'nodisplay'); env.win.document.body.appendChild(parentEle); return parentEle.buildInternal(); }); it('should insert analytics after LOAD_START', function* () { resolver(config); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; parentEle.layoutCallback(); //parentEle.signals().signal(CommonSignals.LOAD_START); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.not.be.null; }); it('should insert analytics when config arrives late', function* () { parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; resolver(config); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.not.be.null; }); it('should remove analytics after UNLOAD', function* () { resolver(config); parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.not.be.null; parentEle.unlayoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; }); it('should NOT insert analytics after UNLOAD', function* () { parentEle.layoutCallback(); yield macroTask(); parentEle.unlayoutCallback(); yield macroTask(); resolver(config); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; }); }); describe('parent does NOT relayout, call in layoutCallback', () => { beforeEach(() => { const promise = new Promise((resolve) => { resolver = resolve; }); class TestElement extends BaseElement { layoutCallback() { useAnalyticsInSandbox(this.element, promise); return super.layoutCallback(); } } registerElement(env.win, 'amp-test', TestElement); parentEle = env.win.document.createElement('amp-test'); parentEle.setAttribute('layout', 'nodisplay'); env.win.document.body.appendChild(parentEle); return parentEle.buildInternal(); }); it('should insert and remove analytics', function* () { expect(parentEle.querySelector('amp-analytics')).to.be.null; parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; resolver(config); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.not.be.null; parentEle.unlayoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; }); }); describe('parent relayout, call in buildCallback', () => { beforeEach(() => { const promise = new Promise((resolve) => { resolver = resolve; }); class TestElement extends BaseElement { buildCallback() { useAnalyticsInSandbox(this.element, promise); } unlayoutCallback() { return true; } } registerElement(env.win, 'amp-test', TestElement); parentEle = env.win.document.createElement('amp-test'); parentEle.setAttribute('layout', 'nodisplay'); env.win.document.body.appendChild(parentEle); return parentEle.buildInternal(); }); it('should NOT insert analytics when relayout', function* () { resolver(config); parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.not.be.null; parentEle.unlayoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; }); it('should NOT insert when config arrives at relayout', function* () { parentEle.layoutCallback(); parentEle.unlayoutCallback(); yield macroTask(); parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; resolver(config); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; }); }); describe('parent relayout, call in layoutCallback', () => { beforeEach(() => { class TestElement extends BaseElement { layoutCallback() { const promise = new Promise((resolve) => { resolver = resolve; }); useAnalyticsInSandbox(this.element, promise); return super.layoutCallback(); } unlayoutCallback() { return true; } } registerElement(env.win, 'amp-test', TestElement); parentEle = env.win.document.createElement('amp-test'); parentEle.setAttribute('layout', 'nodisplay'); env.win.document.body.appendChild(parentEle); return parentEle.buildInternal(); }); it('should insert analytics when relayout', function* () { parentEle.layoutCallback(); resolver(config); yield macroTask(); let element = parentEle.querySelector('amp-analytics'); expect(element).to.not.be.null; let script = element.querySelector('script'); expect(script.textContent).to.jsonEqual(JSON.stringify(config)); parentEle.unlayoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; parentEle.layoutCallback(); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.be.null; resolver(config2); yield macroTask(); expect(parentEle.querySelector('amp-analytics')).to.not.be.null; element = parentEle.querySelector('amp-analytics'); expect(element).to.not.be.null; script = element.querySelector('script'); expect(script.textContent).to.jsonEqual(JSON.stringify(config2)); }); it('should only insert with latest config', function* () { parentEle.layoutCallback(); yield macroTask(); const resolver1 = resolver; parentEle.unlayoutCallback(); parentEle.layoutCallback(); yield macroTask(); const resolver2 = resolver; resolver1(config); resolver2(config2); yield macroTask(); const element = parentEle.querySelector('amp-analytics'); expect(element).to.not.be.null; const script = element.querySelector('script'); expect(script.textContent).to.jsonEqual(JSON.stringify(config2)); }); }); }); } );