| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 52168c7 commit f639513
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -53,7 +53,8 @@ define([ | |||
| 53 | 53 | ||
| 54 | 54 | //Finds variant in specific tests and exec's | |
| 55 | 55 | function run(test, config, context) { | |
| 56 | - if (test.canRun(config, context) && config.switches['ab' + test.id]) { | ||
| 56 | + var expired = (new Date() - new Date(test.expiry)) > 0; | ||
| 57 | + if (test.canRun(config, context) && !expired && config.switches['ab' + test.id]) { | ||
| 57 | 58 | // if user not in test, bucket them | |
| 58 | 59 | if (!isParticipating(test)) { | |
| 59 | 60 | bucket(test); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -127,7 +127,17 @@ define(['modules/experiments/ab', '../fixtures/ab-test'], function(ab, ABTest) { | |||
| 127 | 127 | ||
| 128 | 128 | it('should not bucket user if test can\'t be run', function() { | |
| 129 | 129 | test.canRun = function() { return false; } | |
| 130 | + ab.init({ | ||
| 131 | + switches: { | ||
| 132 | + abDummyTest: true | ||
| 133 | + } | ||
| 134 | + }); | ||
| 135 | + expect(controlSpy.called || variantSpy.called).toBeFalsy(); | ||
| 136 | + expect(ab.getParticipations()).toEqual([]); | ||
| 137 | + }); | ||
| 130 | 138 | ||
| 139 | + it('should expire the test after the expiry date', function () { | ||
| 140 | + test.expiry = "2012-01-01"; | ||
| 131 | 141 | ab.init({ | |
| 132 | 142 | switches: { | |
| 133 | 143 | abDummyTest: true | |
@@ -136,6 +146,19 @@ define(['modules/experiments/ab', '../fixtures/ab-test'], function(ab, ABTest) { | |||
| 136 | 146 | expect(controlSpy.called || variantSpy.called).toBeFalsy(); | |
| 137 | 147 | expect(ab.getParticipations()).toEqual([]); | |
| 138 | 148 | }); | |
| 149 | + | ||
| 150 | + it('should run the test if it has not expired', function () { | ||
| 151 | + var f = new Date(); | ||
| 152 | + f.setHours(f.getHours() + 10); | ||
| 153 | + test.expiry; | ||
| 154 | + ab.init({ | ||
| 155 | + switches: { | ||
| 156 | + abDummyTest: true | ||
| 157 | + } | ||
| 158 | + }); | ||
| 159 | + expect(controlSpy.called || variantSpy.called).toBeTruthy(); | ||
| 160 | + }); | ||
| 161 | + | ||
| 139 | 162 | ||
| 140 | 163 | }); | |
| 141 | 164 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -55,6 +55,7 @@ define(['bonzo'], function (bonzo) { | |||
| 55 | 55 | var ExperimentRelatedContent = function () { | |
| 56 | 56 | ||
| 57 | 57 | this.id = 'RelatedContentV2'; | |
| 58 | + this.expiry = "2013-01-01"; | ||
| 58 | 59 | this.audience = 0.2; | |
| 59 | 60 | this.description = 'Hides related content block on article to see if increases click through on most popular'; | |
| 60 | 61 | this.canRun = function(config) { | |
@@ -84,6 +85,7 @@ define(['bonzo'], function (bonzo) { | |||
| 84 | 85 | The AMD module must return an object with the following properties, | |
| 85 | 86 | ||
| 86 | 87 | - id: The unique name of the test. | |
| 88 | + - expiry: The date on which this test is due to stop running. Expressed as a string parsable by the JavaScript Date obejct. | ||
| 87 | 89 | - audience: The ratio of people who you want in the test (Eg, 0.2 = 20%), who will then be split 50/50 between the control and variant. | |
| 88 | 90 | - description: A plain English summary of the test. | |
| 89 | 91 | - canRun: A function to determine if the test is allowed to run (Eg, so you can target individual pages, segments etc.) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,94 @@ | |||
| 1 | + Interactive | ||
| 2 | + ----------- | ||
| 3 | + | ||
| 4 | + This covers interactive content written and commisioned by Guardian development teams. | ||
| 5 | + | ||
| 6 | + ## Embeded and standalone interactives | ||
| 7 | + | ||
| 8 | + The proposal is that Composer is used to write a (i) basic accessible description of the interactive from within an article, (ii) define the URL to | ||
| 9 | + an interactive application associated with that block. | ||
| 10 | + | ||
| 11 | + For example, such a block might look like this :- | ||
| 12 | + | ||
| 13 | + ``` | ||
| 14 | + <body> | ||
| 15 | + <h1>Headline</h1> | ||
| 16 | + <p> | ||
| 17 | + Article paragraph that has been written in Composer. | ||
| 18 | + </p> | ||
| 19 | + | ||
| 20 | + <!-- An accessible description of the interactive --> | ||
| 21 | + | ||
| 22 | + <figure class="interactive" data-interactive="http://path/to/interactive/boot.js"> | ||
| 23 | + <table> | ||
| 24 | + <tr> | ||
| 25 | + <td>North Circular</td> | ||
| 26 | + <td>346</td> | ||
| 27 | + <td>12%</td> | ||
| 28 | + </tr> | ||
| 29 | + ... | ||
| 30 | + </table> | ||
| 31 | + <caption> | ||
| 32 | + This is a chart describing the most polluted roads in London. | ||
| 33 | + </caption> | ||
| 34 | + </figure> | ||
| 35 | + ... | ||
| 36 | + </body> | ||
| 37 | + ``` | ||
| 38 | + | ||
| 39 | + During the bootstrapping of the frontend code we scan the DOM for interactives and `require()` each one. | ||
| 40 | + | ||
| 41 | + The interface between frontend & interactives should therefore follow this sort of pattern, | ||
| 42 | + | ||
| 43 | + ``` | ||
| 44 | + define(['your/dependencies'], function () { | ||
| 45 | + return { | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * | ||
| 49 | + * @param el : The Element of the interactive that is being progressively enhanced. | ||
| 50 | + * @param context : The DOM context this module must work within. | ||
| 51 | + * @param config : The configration object for this page. | ||
| 52 | + * @param mediator : The event system (publish/subscribe) for this page. | ||
| 53 | + * | ||
| 54 | + **/ | ||
| 55 | + | ||
| 56 | + // 'boot' is a standard interface for our application to start the interactive | ||
| 57 | + boot: function (el, context, config, mediator) { | ||
| 58 | + | ||
| 59 | + // do something to bootstrap the interactive | ||
| 60 | + | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + }); | ||
| 64 | + ``` | ||
| 65 | + | ||
| 66 | + This module can be uploaded in to s3. | ||
| 67 | + | ||
| 68 | + What the interactive modules does after this is largely up to whoever is writing it. | ||
| 69 | + | ||
| 70 | + Your `boot` function may simply include an iframe, Eg. | ||
| 71 | + | ||
| 72 | + ``` | ||
| 73 | + boot: function (el, context, config, mediator) { | ||
| 74 | + var iframe = document.createElement('iframe'); | ||
| 75 | + iframe.setAttribute("src", "http://gia.guim.co.uk/2012/05/gay-rights/interactive/flat.html"); | ||
| 76 | + el.appendChild(iframe); | ||
| 77 | + } | ||
| 78 | + ``` | ||
| 79 | + | ||
| 80 | + This means we :- | ||
| 81 | + | ||
| 82 | + - Deprecate the use of a distinct 'interactive' page type (it is just a module in an article). | ||
| 83 | + - Deprecate the use of code objects. | ||
| 84 | + - Move to all interactives being loaded as AMD modules. | ||
| 85 | + | ||
| 86 | + ## Other types of interactives | ||
| 87 | + | ||
| 88 | + There are other types of work that are classified as 'interactive' - galleries, elections coverage, assorted page enhancements. | ||
| 89 | + | ||
| 90 | + I feel this work is best taken on a case by case basis rather than us designing a general system. | ||
| 91 | + | ||
| 92 | + For example, a 3 month election campaign we should hive off some URL space and write a dedicated application for the purpose. | ||
| 93 | + | ||
| 94 | + Or, for things like the NSA rollovers component, are better deployed as part of our main frontend application under an AB test. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments