idsk_frontend_toolkit 7.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis/govuk_frontend_toolkit_gem_push.enc +0 -0
  6. data/.travis/govuk_frontend_toolkit_gem_push.pub +1 -0
  7. data/.travis.yml +23 -0
  8. data/CONTRIBUTING.md +13 -0
  9. data/Gemfile +3 -0
  10. data/LICENCE +20 -0
  11. data/README.md +61 -0
  12. data/Rakefile +10 -0
  13. data/app/assets/.gitignore +5 -0
  14. data/app/assets/.ruby-version +1 -0
  15. data/app/assets/.travis/README.md +23 -0
  16. data/app/assets/.travis/govuk_frontend_toolkit_push.enc +0 -0
  17. data/app/assets/.travis/govuk_frontend_toolkit_push.pub +1 -0
  18. data/app/assets/.travis.yml +18 -0
  19. data/app/assets/CHANGELOG.md +381 -0
  20. data/app/assets/CONTRIBUTING.md +23 -0
  21. data/app/assets/Gemfile +4 -0
  22. data/app/assets/Gemfile.lock +48 -0
  23. data/app/assets/Gruntfile.js +68 -0
  24. data/app/assets/LICENCE +20 -0
  25. data/app/assets/README.md +170 -0
  26. data/app/assets/VERSION.txt +1 -0
  27. data/app/assets/create-release.sh +38 -0
  28. data/app/assets/docs/analytics.md +270 -0
  29. data/app/assets/docs/functions.md +62 -0
  30. data/app/assets/docs/javascript.md +337 -0
  31. data/app/assets/docs/mixins.md +617 -0
  32. data/app/assets/images/accordion-arrow-2x.png +0 -0
  33. data/app/assets/images/accordion-arrow.png +0 -0
  34. data/app/assets/images/arrow-sprite.png +0 -0
  35. data/app/assets/images/crests/bis_crest_13px.png +0 -0
  36. data/app/assets/images/crests/bis_crest_13px_x2.png +0 -0
  37. data/app/assets/images/crests/bis_crest_18px.png +0 -0
  38. data/app/assets/images/crests/bis_crest_18px_x2.png +0 -0
  39. data/app/assets/images/crests/bis_crest_27px.png +0 -0
  40. data/app/assets/images/crests/bis_crest_27px_x2.png +0 -0
  41. data/app/assets/images/crests/coastguard_13px.png +0 -0
  42. data/app/assets/images/crests/coastguard_13px_x2.png +0 -0
  43. data/app/assets/images/crests/coastguard_18px.png +0 -0
  44. data/app/assets/images/crests/coastguard_18px_x2.png +0 -0
  45. data/app/assets/images/crests/coastguard_27px.png +0 -0
  46. data/app/assets/images/crests/coastguard_27px_x2.png +0 -0
  47. data/app/assets/images/crests/dit_crest_13px.png +0 -0
  48. data/app/assets/images/crests/dit_crest_13px_x2.png +0 -0
  49. data/app/assets/images/crests/dit_crest_18px.png +0 -0
  50. data/app/assets/images/crests/dit_crest_18px_x2.png +0 -0
  51. data/app/assets/images/crests/dit_crest_27px.png +0 -0
  52. data/app/assets/images/crests/dit_crest_27px_x2.png +0 -0
  53. data/app/assets/images/crests/hmrc_crest_13px.png +0 -0
  54. data/app/assets/images/crests/hmrc_crest_13px_x2.png +0 -0
  55. data/app/assets/images/crests/hmrc_crest_18px.png +0 -0
  56. data/app/assets/images/crests/hmrc_crest_18px_x2.png +0 -0
  57. data/app/assets/images/crests/hmrc_crest_27px.png +0 -0
  58. data/app/assets/images/crests/hmrc_crest_27px_x2.png +0 -0
  59. data/app/assets/images/crests/ho_crest_13px.png +0 -0
  60. data/app/assets/images/crests/ho_crest_13px_x2.png +0 -0
  61. data/app/assets/images/crests/ho_crest_18px.png +0 -0
  62. data/app/assets/images/crests/ho_crest_18px_x2.png +0 -0
  63. data/app/assets/images/crests/ho_crest_27px.png +0 -0
  64. data/app/assets/images/crests/ho_crest_27px_x2.png +0 -0
  65. data/app/assets/images/crests/mod_crest_13px.png +0 -0
  66. data/app/assets/images/crests/mod_crest_13px_x2.png +0 -0
  67. data/app/assets/images/crests/mod_crest_18px.png +0 -0
  68. data/app/assets/images/crests/mod_crest_18px_x2.png +0 -0
  69. data/app/assets/images/crests/mod_crest_27px.png +0 -0
  70. data/app/assets/images/crests/mod_crest_27px_x2.png +0 -0
  71. data/app/assets/images/crests/org_crest_13px.png +0 -0
  72. data/app/assets/images/crests/org_crest_13px_x2.png +0 -0
  73. data/app/assets/images/crests/org_crest_18px.png +0 -0
  74. data/app/assets/images/crests/org_crest_18px_x2.png +0 -0
  75. data/app/assets/images/crests/org_crest_27px.png +0 -0
  76. data/app/assets/images/crests/org_crest_27px_x2.png +0 -0
  77. data/app/assets/images/crests/portcullis_13px.png +0 -0
  78. data/app/assets/images/crests/portcullis_13px_x2.png +0 -0
  79. data/app/assets/images/crests/portcullis_18px.png +0 -0
  80. data/app/assets/images/crests/portcullis_18px_x2.png +0 -0
  81. data/app/assets/images/crests/portcullis_27px.png +0 -0
  82. data/app/assets/images/crests/portcullis_27px_x2.png +0 -0
  83. data/app/assets/images/crests/so_crest_13px.png +0 -0
  84. data/app/assets/images/crests/so_crest_13px_x2.png +0 -0
  85. data/app/assets/images/crests/so_crest_18px.png +0 -0
  86. data/app/assets/images/crests/so_crest_18px_x2.png +0 -0
  87. data/app/assets/images/crests/so_crest_27px.png +0 -0
  88. data/app/assets/images/crests/so_crest_27px_x2.png +0 -0
  89. data/app/assets/images/crests/ukaea_crest_13px.png +0 -0
  90. data/app/assets/images/crests/ukaea_crest_13px_x2.png +0 -0
  91. data/app/assets/images/crests/ukaea_crest_18px.png +0 -0
  92. data/app/assets/images/crests/ukaea_crest_18px_x2.png +0 -0
  93. data/app/assets/images/crests/ukaea_crest_27px.png +0 -0
  94. data/app/assets/images/crests/ukaea_crest_27px_x2.png +0 -0
  95. data/app/assets/images/crests/ukho_13px.png +0 -0
  96. data/app/assets/images/crests/ukho_13px_x2.png +0 -0
  97. data/app/assets/images/crests/ukho_18px.png +0 -0
  98. data/app/assets/images/crests/ukho_18px_x2.png +0 -0
  99. data/app/assets/images/crests/ukho_27px.png +0 -0
  100. data/app/assets/images/crests/ukho_27px_x2.png +0 -0
  101. data/app/assets/images/crests/wales_crest_13px.png +0 -0
  102. data/app/assets/images/crests/wales_crest_13px_x2.png +0 -0
  103. data/app/assets/images/crests/wales_crest_18px.png +0 -0
  104. data/app/assets/images/crests/wales_crest_18px_x2.png +0 -0
  105. data/app/assets/images/crests/wales_crest_27px.png +0 -0
  106. data/app/assets/images/crests/wales_crest_27px_x2.png +0 -0
  107. data/app/assets/images/icon-arrow-left.png +0 -0
  108. data/app/assets/images/icon-calendar-2x.png +0 -0
  109. data/app/assets/images/icon-calendar.png +0 -0
  110. data/app/assets/images/icon-file-download-2x.png +0 -0
  111. data/app/assets/images/icon-file-download.png +0 -0
  112. data/app/assets/images/icon-important-2x.png +0 -0
  113. data/app/assets/images/icon-important.png +0 -0
  114. data/app/assets/images/icon-information-2x.png +0 -0
  115. data/app/assets/images/icon-information.png +0 -0
  116. data/app/assets/images/icon-locator-2x.png +0 -0
  117. data/app/assets/images/icon-locator.png +0 -0
  118. data/app/assets/images/icon-pointer-2x.png +0 -0
  119. data/app/assets/images/icon-pointer-black-2x.png +0 -0
  120. data/app/assets/images/icon-pointer-black.png +0 -0
  121. data/app/assets/images/icon-pointer-indexed.png +0 -0
  122. data/app/assets/images/icon-pointer.png +0 -0
  123. data/app/assets/images/icon-search-2x.png +0 -0
  124. data/app/assets/images/icon-search.png +0 -0
  125. data/app/assets/images/icon-steps/icon-step-1-2x.png +0 -0
  126. data/app/assets/images/icon-steps/icon-step-1.png +0 -0
  127. data/app/assets/images/icon-steps/icon-step-10-2x.png +0 -0
  128. data/app/assets/images/icon-steps/icon-step-10.png +0 -0
  129. data/app/assets/images/icon-steps/icon-step-11-2x.png +0 -0
  130. data/app/assets/images/icon-steps/icon-step-11.png +0 -0
  131. data/app/assets/images/icon-steps/icon-step-12-2x.png +0 -0
  132. data/app/assets/images/icon-steps/icon-step-12.png +0 -0
  133. data/app/assets/images/icon-steps/icon-step-13-2x.png +0 -0
  134. data/app/assets/images/icon-steps/icon-step-13.png +0 -0
  135. data/app/assets/images/icon-steps/icon-step-14-2x.png +0 -0
  136. data/app/assets/images/icon-steps/icon-step-14.png +0 -0
  137. data/app/assets/images/icon-steps/icon-step-2-2x.png +0 -0
  138. data/app/assets/images/icon-steps/icon-step-2.png +0 -0
  139. data/app/assets/images/icon-steps/icon-step-3-2x.png +0 -0
  140. data/app/assets/images/icon-steps/icon-step-3.png +0 -0
  141. data/app/assets/images/icon-steps/icon-step-4-2x.png +0 -0
  142. data/app/assets/images/icon-steps/icon-step-4.png +0 -0
  143. data/app/assets/images/icon-steps/icon-step-5-2x.png +0 -0
  144. data/app/assets/images/icon-steps/icon-step-5.png +0 -0
  145. data/app/assets/images/icon-steps/icon-step-6-2x.png +0 -0
  146. data/app/assets/images/icon-steps/icon-step-6.png +0 -0
  147. data/app/assets/images/icon-steps/icon-step-7-2x.png +0 -0
  148. data/app/assets/images/icon-steps/icon-step-7.png +0 -0
  149. data/app/assets/images/icon-steps/icon-step-8-2x.png +0 -0
  150. data/app/assets/images/icon-steps/icon-step-8.png +0 -0
  151. data/app/assets/images/icon-steps/icon-step-9-2x.png +0 -0
  152. data/app/assets/images/icon-steps/icon-step-9.png +0 -0
  153. data/app/assets/images/player-icon-forward.png +0 -0
  154. data/app/assets/images/player-icon-pause.png +0 -0
  155. data/app/assets/images/player-icon-play.png +0 -0
  156. data/app/assets/images/player-icon-rewind.png +0 -0
  157. data/app/assets/images/player-icon-volume.png +0 -0
  158. data/app/assets/images/separator-2x.png +0 -0
  159. data/app/assets/images/separator.png +0 -0
  160. data/app/assets/javascripts/govuk/analytics/analytics.js +143 -0
  161. data/app/assets/javascripts/govuk/analytics/download-link-tracker.js +41 -0
  162. data/app/assets/javascripts/govuk/analytics/error-tracking.js +51 -0
  163. data/app/assets/javascripts/govuk/analytics/external-link-tracker.js +56 -0
  164. data/app/assets/javascripts/govuk/analytics/google-analytics-universal-tracker.js +166 -0
  165. data/app/assets/javascripts/govuk/analytics/govuk-tracker.js +134 -0
  166. data/app/assets/javascripts/govuk/analytics/mailto-link-tracker.js +38 -0
  167. data/app/assets/javascripts/govuk/analytics/print-intent.js +39 -0
  168. data/app/assets/javascripts/govuk/details.polyfill.js +240 -0
  169. data/app/assets/javascripts/govuk/modules/auto-track-event.js +30 -0
  170. data/app/assets/javascripts/govuk/modules.js +61 -0
  171. data/app/assets/javascripts/govuk/primary-links.js +57 -0
  172. data/app/assets/javascripts/govuk/selection-buttons.js +116 -0
  173. data/app/assets/javascripts/govuk/shim-links-with-button-role.js +34 -0
  174. data/app/assets/javascripts/govuk/show-hide-content.js +172 -0
  175. data/app/assets/javascripts/govuk/stick-at-top-when-scrolling.js +128 -0
  176. data/app/assets/javascripts/govuk/stop-scrolling-at-footer.js +139 -0
  177. data/app/assets/javascripts/govuk_toolkit.js +1 -0
  178. data/app/assets/javascripts/stageprompt.js +69 -0
  179. data/app/assets/javascripts/vendor/jquery/jquery.player.min.js +25 -0
  180. data/app/assets/javascripts/vendor/polyfills/bind.js +40 -0
  181. data/app/assets/package.json +25 -0
  182. data/app/assets/spec/manifest.js +41 -0
  183. data/app/assets/spec/stylesheets/_colour_contrast_spec.scss +12 -0
  184. data/app/assets/spec/support/LocalTestRunner.html +21 -0
  185. data/app/assets/spec/support/console-runner.js +102 -0
  186. data/app/assets/spec/support/load.js +47 -0
  187. data/app/assets/spec/support/run_jasmine_test.js +62 -0
  188. data/app/assets/spec/unit/analytics/analytics.spec.js +315 -0
  189. data/app/assets/spec/unit/analytics/download-link-tracker.spec.js +72 -0
  190. data/app/assets/spec/unit/analytics/error-tracking.spec.js +65 -0
  191. data/app/assets/spec/unit/analytics/external-link-tracker.spec.js +109 -0
  192. data/app/assets/spec/unit/analytics/google-analytics-universal-tracker.spec.js +180 -0
  193. data/app/assets/spec/unit/analytics/govuk-tracker.spec.js +171 -0
  194. data/app/assets/spec/unit/analytics/mailto-link-tracker.spec.js +62 -0
  195. data/app/assets/spec/unit/details.polyfill.spec.js +91 -0
  196. data/app/assets/spec/unit/modules/auto-track-event.spec.js +54 -0
  197. data/app/assets/spec/unit/modules.spec.js +93 -0
  198. data/app/assets/spec/unit/primary-links.spec.js +55 -0
  199. data/app/assets/spec/unit/selection-button.spec.js +761 -0
  200. data/app/assets/spec/unit/shim-links-with-button-role.spec.js +41 -0
  201. data/app/assets/spec/unit/show-hide-content.spec.js +306 -0
  202. data/app/assets/spec/unit/stick-at-top-when-scrolling.spec.js +137 -0
  203. data/app/assets/stylesheets/.gitkeep +0 -0
  204. data/app/assets/stylesheets/_colours.scss +2 -0
  205. data/app/assets/stylesheets/_conditionals.scss +81 -0
  206. data/app/assets/stylesheets/_css3.scss +90 -0
  207. data/app/assets/stylesheets/_device-pixels.scss +10 -0
  208. data/app/assets/stylesheets/_font_stack.scss +25 -0
  209. data/app/assets/stylesheets/_grid_layout.scss +136 -0
  210. data/app/assets/stylesheets/_helpers.scss +16 -0
  211. data/app/assets/stylesheets/_measurements.scss +14 -0
  212. data/app/assets/stylesheets/_shims.scss +55 -0
  213. data/app/assets/stylesheets/_typography.scss +249 -0
  214. data/app/assets/stylesheets/_url-helpers.scss +16 -0
  215. data/app/assets/stylesheets/colours/_organisation.scss +104 -0
  216. data/app/assets/stylesheets/colours/_palette.scss +77 -0
  217. data/app/assets/stylesheets/design-patterns/_alpha-beta.scss +67 -0
  218. data/app/assets/stylesheets/design-patterns/_breadcrumbs.scss +53 -0
  219. data/app/assets/stylesheets/design-patterns/_buttons.scss +145 -0
  220. data/app/assets/stylesheets/design-patterns/_media-player.scss +264 -0
  221. data/app/assets/trigger.sh +24 -0
  222. data/idsk_frontend_toolkit.gemspec +49 -0
  223. data/lib/idsk_frontend_toolkit/engine.rb +4 -0
  224. data/lib/idsk_frontend_toolkit/version.rb +5 -0
  225. data/lib/idsk_frontend_toolkit.rb +4 -0
  226. data/publish.sh +30 -0
  227. metadata +314 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Runs a Jasmine Suite from an html page.
3
+ * `page` is a PhantomJs page object.
4
+ * `exit_func` is the function to call in order to exit the script.
5
+ */
6
+
7
+ var PhantomJasmineRunner, address, page, runner;
8
+
9
+ PhantomJasmineRunner = (function() {
10
+
11
+ function PhantomJasmineRunner(page, exit_func) {
12
+ this.page = page;
13
+ this.exit_func = exit_func != null ? exit_func : phantom.exit;
14
+ this.tries = 0;
15
+ this.max_tries = 10;
16
+ }
17
+
18
+ PhantomJasmineRunner.prototype.get_status = function() {
19
+ return this.page.evaluate(function() {
20
+ return console_reporter.status;
21
+ });
22
+ };
23
+
24
+ PhantomJasmineRunner.prototype.terminate = function() {
25
+ switch (this.get_status()) {
26
+ case "success":
27
+ return this.exit_func(0);
28
+ case "fail":
29
+ return this.exit_func(1);
30
+ default:
31
+ return this.exit_func(2);
32
+ }
33
+ };
34
+
35
+ return PhantomJasmineRunner;
36
+
37
+ })();
38
+
39
+ if (phantom.args.length === 0) {
40
+ console.log("Need a url as the argument");
41
+ phantom.exit(1);
42
+ }
43
+
44
+ page = new WebPage();
45
+
46
+ runner = new PhantomJasmineRunner(page);
47
+
48
+ page.onConsoleMessage = function(msg) {
49
+ console.log(msg);
50
+ if (msg === "ConsoleReporter finished") {
51
+ return runner.terminate();
52
+ }
53
+ };
54
+
55
+ address = phantom.args[0];
56
+
57
+ page.open(address, function(status) {
58
+ if (status !== "success") {
59
+ console.log("can't load the address!");
60
+ return phantom.exit(1);
61
+ }
62
+ });
@@ -0,0 +1,315 @@
1
+ /* global describe it expect beforeEach jasmine spyOn */
2
+
3
+ describe('GOVUK.Analytics', function () {
4
+ 'use strict'
5
+ var GOVUK = window.GOVUK
6
+
7
+ function addGoogleAnalyticsSpy () {
8
+ window.ga = function () {}
9
+ spyOn(window, 'ga')
10
+ }
11
+
12
+ var analytics
13
+ var universalSetupArguments
14
+
15
+ beforeEach(function () {
16
+ addGoogleAnalyticsSpy()
17
+
18
+ analytics = new GOVUK.Analytics({
19
+ universalId: 'universal-id',
20
+ cookieDomain: '.www.gov.uk',
21
+ siteSpeedSampleRate: 100
22
+ })
23
+ })
24
+
25
+ describe('when created', function () {
26
+ beforeEach(function () {
27
+ universalSetupArguments = window.ga.calls.allArgs()
28
+ })
29
+
30
+ it('configures a universal tracker', function () {
31
+ expect(universalSetupArguments[0]).toEqual(['create', 'universal-id', {cookieDomain: '.www.gov.uk', siteSpeedSampleRate: 100}])
32
+ expect(universalSetupArguments[1]).toEqual(['set', 'anonymizeIp', true])
33
+ expect(universalSetupArguments[2]).toEqual(['set', 'displayFeaturesTask', null])
34
+ })
35
+
36
+ it('is configured not to strip postcode data from GA calls', function () {
37
+ expect(analytics.stripPostcodePII).toEqual(false)
38
+ })
39
+
40
+ it('can be told to strip postcode data from GA calls', function () {
41
+ analytics = new GOVUK.Analytics({
42
+ universalId: 'universal-id',
43
+ cookieDomain: '.www.gov.uk',
44
+ siteSpeedSampleRate: 100,
45
+ stripPostcodePII: true
46
+ })
47
+
48
+ expect(analytics.stripPostcodePII).toEqual(true)
49
+ })
50
+ })
51
+
52
+ describe('extracting the default path for a page view', function () {
53
+ it('returns a path extracted from the location', function () {
54
+ var location = {
55
+ href: 'https://govuk-frontend-toolkit.example.com/a/path',
56
+ origin: 'https://govuk-frontend-toolkit.example.com'
57
+ }
58
+ expect(analytics.defaultPathForTrackPageview(location)).toEqual('/a/path')
59
+ })
60
+
61
+ it('includes the querystring in the path extracted from the location', function () {
62
+ var location = {
63
+ href: 'https://govuk-frontend-toolkit.example.com/a/path?with=a&query=string',
64
+ origin: 'https://govuk-frontend-toolkit.example.com'
65
+ }
66
+ expect(analytics.defaultPathForTrackPageview(location)).toEqual('/a/path?with=a&query=string')
67
+ })
68
+
69
+ it('removes any anchor from the path extracted from the location', function () {
70
+ var location = {
71
+ href: 'https://govuk-frontend-toolkit.example.com/a/path#with-an-anchor',
72
+ origin: 'https://govuk-frontend-toolkit.example.com'
73
+ }
74
+ expect(analytics.defaultPathForTrackPageview(location)).toEqual('/a/path')
75
+ location.href = 'https://govuk-frontend-toolkit.example.com/a/path?with=a&query=string#with-an-anchor'
76
+ expect(analytics.defaultPathForTrackPageview(location)).toEqual('/a/path?with=a&query=string')
77
+ })
78
+ })
79
+
80
+ describe('tracking pageviews', function () {
81
+ beforeEach(function () {
82
+ spyOn(analytics, 'defaultPathForTrackPageview').and.returnValue('/a/page?with=a&query=string')
83
+ })
84
+
85
+ it('injects a default path if no args are supplied', function () {
86
+ analytics.trackPageview()
87
+ console.log(window.ga.calls.mostRecent().args)
88
+ expect(window.ga.calls.mostRecent().args[2].page).toEqual('/a/page?with=a&query=string')
89
+ })
90
+
91
+ it('injects a default path if args are supplied, but the path arg is blank', function () {
92
+ analytics.trackPageview(null)
93
+ console.log(window.ga.calls.mostRecent().args)
94
+ expect(window.ga.calls.mostRecent().args[2].page).toEqual('/a/page?with=a&query=string')
95
+
96
+ analytics.trackPageview(undefined)
97
+ console.log(window.ga.calls.mostRecent().args)
98
+ expect(window.ga.calls.mostRecent().args[2].page).toEqual('/a/page?with=a&query=string')
99
+ })
100
+
101
+ it('uses the supplied path', function () {
102
+ analytics.trackPageview('/foo')
103
+ console.log(window.ga.calls.mostRecent().args)
104
+ expect(window.ga.calls.mostRecent().args[2].page).toEqual('/foo')
105
+ })
106
+
107
+ it('does not inject a default title if no args are supplied', function () {
108
+ analytics.trackPageview()
109
+ console.log(window.ga.calls.mostRecent().args)
110
+ expect(window.ga.calls.mostRecent().args[2].title).toEqual(undefined)
111
+ })
112
+
113
+ it('does not inject a default title if args are supplied, but the title arg is blank', function () {
114
+ analytics.trackPageview('/foo', null)
115
+ console.log(window.ga.calls.mostRecent().args)
116
+ expect(window.ga.calls.mostRecent().args[2].title).toEqual(undefined)
117
+
118
+ analytics.trackPageview('/foo', undefined)
119
+ console.log(window.ga.calls.mostRecent().args)
120
+ expect(window.ga.calls.mostRecent().args[2].title).toEqual(undefined)
121
+ })
122
+
123
+ it('uses the supplied title', function () {
124
+ analytics.trackPageview('/foo', 'A page')
125
+ console.log(window.ga.calls.mostRecent().args)
126
+ expect(window.ga.calls.mostRecent().args[2].title).toEqual('A page')
127
+ })
128
+ })
129
+
130
+ describe('when tracking pageviews, events and custom dimensions', function () {
131
+ it('tracks them in universal analytics', function () {
132
+ analytics.trackPageview('/path', 'Title')
133
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', 'pageview', {page: '/path', title: 'Title'}])
134
+
135
+ analytics.trackEvent('category', 'action')
136
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', {hitType: 'event', eventCategory: 'category', eventAction: 'action'}])
137
+
138
+ analytics.setDimension(1, 'value', 'name')
139
+ expect(window.ga.calls.mostRecent().args).toEqual(['set', 'dimension1', 'value'])
140
+ })
141
+
142
+ it('strips email addresses embedded in arguments', function () {
143
+ analytics.trackPageview('/path/to/an/embedded.email@example.com/address/?with=an&email=in.it@example.com', 'an.email@example.com', { label: 'another.email@example.com', value: ['data', 'data', 'someone has added their personal.email@example.com address'] })
144
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', 'pageview', { page: '/path/to/an/[email]/address/?with=an&email=[email]', title: '[email]', label: '[email]', value: ['data', 'data', 'someone has added their [email] address'] }])
145
+
146
+ analytics.trackEvent('an_email@example.com_address-category', 'an.email@example.com-action', { label: 'another.email@example.com', value: ['data', 'data', 'someone has added their personal.email@example.com address'] })
147
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', { hitType: 'event', eventCategory: '[email]', eventAction: '[email]', eventLabel: '[email]' }]) // trackEvent ignores options other than label or integer values for value
148
+
149
+ analytics.setDimension(1, 'an_email@example.com_address-value', { label: 'another.email@example.com', value: ['data', 'data', 'someone has added their personal.email@example.com address'] })
150
+ expect(window.ga.calls.mostRecent().args).toEqual(['set', 'dimension1', '[email]']) // set dimension ignores extra options
151
+ })
152
+
153
+ it('leaves postcodes embedded in arguments by default', function () {
154
+ analytics.trackPageview('/path/to/an/embedded/SW1+1AA/postcode/?with=an&postcode=SP4%207DE', 'TD15 2SE', { label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
155
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', 'pageview', { page: '/path/to/an/embedded/SW1+1AA/postcode/?with=an&postcode=SP4%207DE', title: 'TD15 2SE', label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] }])
156
+
157
+ analytics.trackEvent('SW1+1AA-category', 'SP4%207DE-action', { label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
158
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', { hitType: 'event', eventCategory: 'SW1+1AA-category', eventAction: 'SP4%207DE-action', eventLabel: 'RG209NJ' }]) // trackEvent ignores options other than label or integer values for value
159
+
160
+ analytics.setDimension(1, 'SW1+1AA-value', { label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
161
+ expect(window.ga.calls.mostRecent().args).toEqual(['set', 'dimension1', 'SW1+1AA-value']) // set dimension ignores extra options
162
+ })
163
+
164
+ it('strips postcodes embedded in arguments if configured to do so', function () {
165
+ analytics = new GOVUK.Analytics({
166
+ universalId: 'universal-id',
167
+ cookieDomain: '.www.gov.uk',
168
+ siteSpeedSampleRate: 100,
169
+ stripPostcodePII: true
170
+ })
171
+
172
+ analytics.trackPageview('/path/to/an/embedded/SW1+1AA/postcode/?with=an&postcode=SP4%207DE', 'TD15 2SE', { label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
173
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', 'pageview', { page: '/path/to/an/embedded/[postcode]/postcode/?with=an&postcode=[postcode]', title: '[postcode]', label: '[postcode]', value: ['data', 'data', 'someone has added their personal[postcode] postcode'] }])
174
+
175
+ analytics.trackEvent('SW1+1AA-category', 'SP4%207DE-action', { label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
176
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', { hitType: 'event', eventCategory: '[postcode]-category', eventAction: '[postcode]-action', eventLabel: '[postcode]' }]) // trackEvent ignores options other than label or integer values for value
177
+
178
+ analytics.setDimension(1, 'SW1+1AA-value', { label: 'RG209NJ', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
179
+ expect(window.ga.calls.mostRecent().args).toEqual(['set', 'dimension1', '[postcode]-value']) // set dimension ignores extra options
180
+ })
181
+
182
+ it('ignores any PIISafe arguments even if they look like emails or postcodes', function () {
183
+ analytics = new GOVUK.Analytics({
184
+ universalId: 'universal-id',
185
+ cookieDomain: '.www.gov.uk',
186
+ siteSpeedSampleRate: 100,
187
+ stripPostcodePII: true
188
+ })
189
+
190
+ analytics.trackPageview(new GOVUK.Analytics.PIISafe('/path/to/an/embedded/SW1+1AA/postcode/?with=an&postcode=SP4%207DE'), new GOVUK.Analytics.PIISafe('an.email@example.com'), { label: new GOVUK.Analytics.PIISafe('another.email@example.com'), value: ['data', 'data', new GOVUK.Analytics.PIISafe('someone has added their personalIV63 6TU postcode')] })
191
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', 'pageview', { page: '/path/to/an/embedded/SW1+1AA/postcode/?with=an&postcode=SP4%207DE', title: 'an.email@example.com', label: 'another.email@example.com', value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] }])
192
+
193
+ analytics.trackEvent(new GOVUK.Analytics.PIISafe('SW1+1AA-category'), new GOVUK.Analytics.PIISafe('an.email@example.com-action'), { label: new GOVUK.Analytics.PIISafe('RG209NJ'), value: ['data', 'data', 'someone has added their personalIV63 6TU postcode'] })
194
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', { hitType: 'event', eventCategory: 'SW1+1AA-category', eventAction: 'an.email@example.com-action', eventLabel: 'RG209NJ' }]) // trackEvent ignores options other than label or integer values for value
195
+
196
+ analytics.setDimension(1, new GOVUK.Analytics.PIISafe('an.email@SW1+1AA-value.com'), { label: new GOVUK.Analytics.PIISafe('RG209NJ'), value: ['data', 'data', new GOVUK.Analytics.PIISafe('someone has added their personalIV63 6TU postcode')] })
197
+ expect(window.ga.calls.mostRecent().args).toEqual(['set', 'dimension1', 'an.email@SW1+1AA-value.com']) // set dimension ignores extra options
198
+ })
199
+ })
200
+
201
+ describe('when tracking social media shares', function () {
202
+ it('tracks in universal', function () {
203
+ analytics.trackShare('network')
204
+
205
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', {
206
+ hitType: 'social',
207
+ socialNetwork: 'network',
208
+ socialAction: 'share',
209
+ socialTarget: jasmine.any(String)
210
+ }])
211
+ })
212
+
213
+ it('strips email addresses embedded in arguments', function () {
214
+ analytics.trackShare('email', {
215
+ to: 'myfriend@example.com',
216
+ label: 'another.email@example.com',
217
+ value: ['data', 'data', 'someone has added their personal.email@example.com address']
218
+ })
219
+
220
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', {
221
+ hitType: 'social',
222
+ socialNetwork: 'email',
223
+ socialAction: 'share',
224
+ socialTarget: jasmine.any(String),
225
+ to: '[email]',
226
+ label: '[email]',
227
+ value: ['data', 'data', 'someone has added their [email] address']
228
+ }])
229
+ })
230
+
231
+ it('leaves postcodes embedded in arguments by default', function () {
232
+ analytics.trackShare('email', {
233
+ to: 'IV63 6TU',
234
+ label: 'SP4%207DE',
235
+ value: ['data', 'data', 'someone has added their personalTD15 2SE postcode']
236
+ })
237
+
238
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', {
239
+ hitType: 'social',
240
+ socialNetwork: 'email',
241
+ socialAction: 'share',
242
+ socialTarget: jasmine.any(String),
243
+ to: 'IV63 6TU',
244
+ label: 'SP4%207DE',
245
+ value: ['data', 'data', 'someone has added their personalTD15 2SE postcode']
246
+ }])
247
+ })
248
+
249
+ it('strips postcodes embedded in arguments if configured to do so', function () {
250
+ analytics = new GOVUK.Analytics({
251
+ universalId: 'universal-id',
252
+ cookieDomain: '.www.gov.uk',
253
+ siteSpeedSampleRate: 100,
254
+ stripPostcodePII: true
255
+ })
256
+
257
+ analytics.trackShare('email', {
258
+ to: 'IV63 6TU',
259
+ label: 'SP4%207DE',
260
+ value: ['data', 'data', 'someone has added their personalTD15 2SE postcode']
261
+ })
262
+
263
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', {
264
+ hitType: 'social',
265
+ socialNetwork: 'email',
266
+ socialAction: 'share',
267
+ socialTarget: jasmine.any(String),
268
+ to: '[postcode]',
269
+ label: '[postcode]',
270
+ value: ['data', 'data', 'someone has added their personal[postcode] postcode']
271
+ }])
272
+ })
273
+
274
+ it('ignores any PIISafe arguments even if they look like emails or postcodes', function () {
275
+ analytics = new GOVUK.Analytics({
276
+ universalId: 'universal-id',
277
+ cookieDomain: '.www.gov.uk',
278
+ siteSpeedSampleRate: 100,
279
+ stripPostcodePII: true
280
+ })
281
+
282
+ analytics.trackShare('email', {
283
+ to: new GOVUK.Analytics.PIISafe('IV63 6TU'),
284
+ label: new GOVUK.Analytics.PIISafe('an.email@example.com'),
285
+ value: new GOVUK.Analytics.PIISafe(['data', 'another.email@example.com', 'someone has added their personalTD15 2SE postcode'])
286
+ })
287
+
288
+ expect(window.ga.calls.mostRecent().args).toEqual(['send', {
289
+ hitType: 'social',
290
+ socialNetwork: 'email',
291
+ socialAction: 'share',
292
+ socialTarget: jasmine.any(String),
293
+ to: 'IV63 6TU',
294
+ label: 'an.email@example.com',
295
+ value: ['data', 'another.email@example.com', 'someone has added their personalTD15 2SE postcode']
296
+ }])
297
+ })
298
+ })
299
+
300
+ describe('when adding a linked domain', function () {
301
+ it('adds a linked domain to universal analytics', function () {
302
+ analytics.addLinkedTrackerDomain('1234', 'test', 'www.example.com')
303
+
304
+ var allArgs = window.ga.calls.allArgs()
305
+ expect(allArgs).toContain(['create', '1234', 'auto', {'name': 'test'}])
306
+ expect(allArgs).toContain(['require', 'linker'])
307
+ expect(allArgs).toContain(['test.require', 'linker'])
308
+ expect(allArgs).toContain(['linker:autoLink', ['www.example.com']])
309
+ expect(allArgs).toContain(['test.linker:autoLink', ['www.example.com']])
310
+ expect(allArgs).toContain(['test.set', 'anonymizeIp', true])
311
+ expect(allArgs).toContain(['test.set', 'displayFeaturesTask', null])
312
+ expect(allArgs).toContain(['test.send', 'pageview'])
313
+ })
314
+ })
315
+ })
@@ -0,0 +1,72 @@
1
+ /* global describe it expect beforeEach afterEach spyOn */
2
+
3
+ var $ = window.jQuery
4
+
5
+ describe('GOVUK.analyticsPlugins.downloadLinkTracker', function () {
6
+ 'use strict'
7
+ var GOVUK = window.GOVUK
8
+
9
+ var $links
10
+
11
+ beforeEach(function () {
12
+ $links = $(
13
+ '<div class="download-links">' +
14
+ '<a href="/one.pdf">PDF</a>' +
15
+ '<a href="/two.xslt">Spreadsheet</a>' +
16
+ '<a href="/something/uploads/system/three.doc">Document</a>' +
17
+ '<a href="/an/image/link.png"><img src="/img" /></a>' +
18
+ '</div>' +
19
+ '<div class="normal-links">' +
20
+ '<a href="/normal-link">Normal link</a>' +
21
+ '<a href="/another-link">Another link</a>' +
22
+ '</div>'
23
+ )
24
+
25
+ $('html').on('click', function (evt) { evt.preventDefault() })
26
+ $('body').append($links)
27
+ GOVUK.analytics = {trackEvent: function () {}}
28
+ GOVUK.analyticsPlugins.downloadLinkTracker({selector: 'a[href$=".pdf"], a[href$=".xslt"], a[href$=".doc"], a[href$=".png"]'})
29
+ })
30
+
31
+ afterEach(function () {
32
+ $('html').off()
33
+ $('body').off()
34
+ $links.remove()
35
+ delete GOVUK.analytics
36
+ })
37
+
38
+ it('listens to clicks on links that match the selector', function () {
39
+ spyOn(GOVUK.analytics, 'trackEvent')
40
+
41
+ $('.download-links a').each(function () {
42
+ $(this).trigger('click')
43
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalled()
44
+ GOVUK.analytics.trackEvent.calls.reset()
45
+ })
46
+
47
+ $('.normal-links a').each(function () {
48
+ $(this).trigger('click')
49
+ expect(GOVUK.analytics.trackEvent).not.toHaveBeenCalled()
50
+ GOVUK.analytics.trackEvent.calls.reset()
51
+ })
52
+ })
53
+
54
+ it('listens to click events on elements within download links', function () {
55
+ spyOn(GOVUK.analytics, 'trackEvent')
56
+
57
+ $('.download-links a img').trigger('click')
58
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith('Download Link Clicked', '/an/image/link.png', {transport: 'beacon'})
59
+ })
60
+
61
+ it('tracks a download link as an event with link text as the label', function () {
62
+ spyOn(GOVUK.analytics, 'trackEvent')
63
+ $('.download-links a').trigger('click')
64
+
65
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
66
+ 'Download Link Clicked', '/one.pdf', {label: 'PDF', transport: 'beacon'})
67
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
68
+ 'Download Link Clicked', '/two.xslt', {label: 'Spreadsheet', transport: 'beacon'})
69
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
70
+ 'Download Link Clicked', '/something/uploads/system/three.doc', {label: 'Document', transport: 'beacon'})
71
+ })
72
+ })
@@ -0,0 +1,65 @@
1
+ /* global describe it expect beforeEach afterEach spyOn */
2
+
3
+ describe('GOVUK.analyticsPlugins.error', function () {
4
+ 'use strict'
5
+ var GOVUK = window.GOVUK
6
+
7
+ GOVUK.analyticsPlugins.error({filenameMustMatch: /gov\.uk/})
8
+
9
+ beforeEach(function () {
10
+ GOVUK.analytics = {trackEvent: function () {}}
11
+ spyOn(GOVUK.analytics, 'trackEvent')
12
+ })
13
+
14
+ afterEach(function () {
15
+ delete GOVUK.analytics
16
+ })
17
+
18
+ it('sends errors to Google Analytics', function () {
19
+ triggerError('https://www.gov.uk/filename.js', 2, 'Error message')
20
+
21
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
22
+ 'JavaScript Error',
23
+ 'Error message',
24
+ { label: 'https://www.gov.uk/filename.js: 2', value: 1, nonInteraction: true })
25
+ })
26
+
27
+ it('tracks only errors with a matching or blank filename', function () {
28
+ triggerError('http://www.gov.uk/somefile.js', 2, 'Error message')
29
+ triggerError('', 2, 'In page error')
30
+ triggerError('http://www.broken-external-plugin-site.com/horrible.js', 2, 'Error message')
31
+
32
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
33
+ 'JavaScript Error',
34
+ 'Error message',
35
+ {
36
+ label: 'http://www.gov.uk/somefile.js: 2',
37
+ value: 1,
38
+ nonInteraction: true })
39
+
40
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
41
+ 'JavaScript Error',
42
+ 'In page error',
43
+ {
44
+ label: ': 2',
45
+ value: 1,
46
+ nonInteraction: true })
47
+
48
+ expect(GOVUK.analytics.trackEvent).not.toHaveBeenCalledWith(
49
+ 'JavaScript Error',
50
+ 'Error message',
51
+ {
52
+ label: 'http://www.broken-external-plugin-site.com/horrible.js: 2',
53
+ value: 1,
54
+ nonInteraction: true })
55
+ })
56
+
57
+ function triggerError (filename, lineno, message) {
58
+ var event = document.createEvent('Event')
59
+ event.initEvent('error', true, true)
60
+ event.filename = filename
61
+ event.lineno = lineno
62
+ event.message = message
63
+ window.dispatchEvent(event)
64
+ }
65
+ })
@@ -0,0 +1,109 @@
1
+ /* global describe it expect beforeEach afterEach spyOn */
2
+
3
+ var $ = window.jQuery
4
+
5
+ describe('GOVUK.analyticsPlugins.externalLinkTracker', function () {
6
+ 'use strict'
7
+ var GOVUK = window.GOVUK
8
+
9
+ var $links
10
+
11
+ beforeEach(function () {
12
+ $links = $(
13
+ '<div class="external-links">' +
14
+ '<a href="http://www.nationalarchives.gov.uk"> National Archives </a>' +
15
+ '<a href="https://www.nationalarchives.gov.uk"></a>' +
16
+ '<a href="https://www.nationalarchives.gov.uk/one.pdf">National Archives PDF</a>' +
17
+ '<a href="https://www.nationalarchives.gov.uk/an/image/link.png"><img src="/img" /></a>' +
18
+ '</div>' +
19
+ '<div class="internal-links">' +
20
+ '<a href="/some-path">Local link</a>' +
21
+ '<a href="http://fake-hostname.com/some-path">Another local link</a>' +
22
+ '</div>'
23
+ )
24
+
25
+ $('html').on('click', function (evt) { evt.preventDefault() })
26
+ $('body').append($links)
27
+ GOVUK.analytics = {
28
+ trackEvent: function () {},
29
+ setDimension: function () {}
30
+ }
31
+
32
+ spyOn(GOVUK.analyticsPlugins.externalLinkTracker, 'getHostname').and.returnValue('fake-hostname.com')
33
+ })
34
+
35
+ afterEach(function () {
36
+ $('html').off()
37
+ $('body').off()
38
+ $links.remove()
39
+ delete GOVUK.analytics
40
+ })
41
+
42
+ it('listens to click events on only external links', function () {
43
+ GOVUK.analyticsPlugins.externalLinkTracker({externalLinkUploadCustomDimension: 36})
44
+
45
+ spyOn(GOVUK.analytics, 'trackEvent')
46
+
47
+ $('.external-links a').each(function () {
48
+ $(this).trigger('click')
49
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalled()
50
+ GOVUK.analytics.trackEvent.calls.reset()
51
+ })
52
+
53
+ $('.internal-links a').each(function () {
54
+ $(this).trigger('click')
55
+ expect(GOVUK.analytics.trackEvent).not.toHaveBeenCalled()
56
+ GOVUK.analytics.trackEvent.calls.reset()
57
+ })
58
+ })
59
+
60
+ it('listens to click events on elements within external links', function () {
61
+ GOVUK.analyticsPlugins.externalLinkTracker({externalLinkUploadCustomDimension: 36})
62
+
63
+ spyOn(GOVUK.analytics, 'trackEvent')
64
+
65
+ $('.external-links a img').trigger('click')
66
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
67
+ 'External Link Clicked', 'https://www.nationalarchives.gov.uk/an/image/link.png', {transport: 'beacon'})
68
+ })
69
+
70
+ it('tracks an external link\'s href and link text', function () {
71
+ GOVUK.analyticsPlugins.externalLinkTracker({externalLinkUploadCustomDimension: 36})
72
+
73
+ spyOn(GOVUK.analytics, 'trackEvent')
74
+ $('.external-links a').trigger('click')
75
+
76
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
77
+ 'External Link Clicked', 'http://www.nationalarchives.gov.uk', {transport: 'beacon', label: 'National Archives'})
78
+
79
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
80
+ 'External Link Clicked', 'https://www.nationalarchives.gov.uk', {transport: 'beacon'})
81
+
82
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
83
+ 'External Link Clicked', 'https://www.nationalarchives.gov.uk/one.pdf', {transport: 'beacon', label: 'National Archives PDF'})
84
+ })
85
+
86
+ it('duplicates the url info in a custom dimension to be used to join with a Google Analytics upload', function () {
87
+ GOVUK.analyticsPlugins.externalLinkTracker({externalLinkUploadCustomDimension: 36})
88
+
89
+ spyOn(GOVUK.analytics, 'setDimension')
90
+ spyOn(GOVUK.analytics, 'trackEvent')
91
+ $('.external-links a').trigger('click')
92
+
93
+ expect(GOVUK.analytics.setDimension).toHaveBeenCalledWith(36, 'http://www.nationalarchives.gov.uk')
94
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
95
+ 'External Link Clicked', 'http://www.nationalarchives.gov.uk', {transport: 'beacon', label: 'National Archives'})
96
+ })
97
+
98
+ it('does not duplicate the url info if a custom dimension is not provided', function () {
99
+ GOVUK.analyticsPlugins.externalLinkTracker()
100
+
101
+ spyOn(GOVUK.analytics, 'setDimension')
102
+ spyOn(GOVUK.analytics, 'trackEvent')
103
+ $('.external-links a').trigger('click')
104
+
105
+ expect(GOVUK.analytics.setDimension).not.toHaveBeenCalled()
106
+ expect(GOVUK.analytics.trackEvent).toHaveBeenCalledWith(
107
+ 'External Link Clicked', 'http://www.nationalarchives.gov.uk', {transport: 'beacon', label: 'National Archives'})
108
+ })
109
+ })