Commit baaebabb authored by Jay's avatar Jay Committed by Vitaly Slobodin

Add GLEX frontend experiment helpers/spec helpers

parent 9fea86e8
export const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0'; export const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0';
export const DEFAULT_VARIANT = 'control'; export const DEFAULT_VARIANT = 'control';
export const CANDIDATE_VARIANT = 'candidate';
// This file only applies to use of experiments through https://gitlab.com/gitlab-org/gitlab-experiment // This file only applies to use of experiments through https://gitlab.com/gitlab-org/gitlab-experiment
import { get } from 'lodash'; import { get } from 'lodash';
import { DEFAULT_VARIANT } from './constants'; import { DEFAULT_VARIANT, CANDIDATE_VARIANT } from './constants';
export function getExperimentData(experimentName) { export function getExperimentData(experimentName) {
return get(window, ['gon', 'experiment', experimentName]); return get(window, ['gon', 'experiment', experimentName]);
...@@ -13,3 +13,16 @@ export function isExperimentVariant(experimentName, variantName) { ...@@ -13,3 +13,16 @@ export function isExperimentVariant(experimentName, variantName) {
export function getExperimentVariant(experimentName) { export function getExperimentVariant(experimentName) {
return getExperimentData(experimentName)?.variant || DEFAULT_VARIANT; return getExperimentData(experimentName)?.variant || DEFAULT_VARIANT;
} }
export function experiment(experimentName, variants) {
const variant = getExperimentVariant(experimentName);
switch (variant) {
case DEFAULT_VARIANT:
return variants.use.call();
case CANDIDATE_VARIANT:
return variants.try.call();
default:
return variants[variant].call();
}
}
...@@ -12,3 +12,16 @@ export function withGonExperiment(experimentKey, value = true) { ...@@ -12,3 +12,16 @@ export function withGonExperiment(experimentKey, value = true) {
window.gon = origGon; window.gon = origGon;
}); });
} }
// This helper is for specs that use `gitlab-experiment` utilities, which have a different schema that gets pushed via Gon compared to `Experimentation Module`
export function assignGitlabExperiment(experimentKey, variant) {
let origGon;
beforeEach(() => {
origGon = window.gon;
window.gon = { experiment: { [experimentKey]: { variant } } };
});
afterEach(() => {
window.gon = origGon;
});
}
import { DEFAULT_VARIANT } from '~/experimentation/constants'; import { assignGitlabExperiment } from 'helpers/experimentation_helper';
import { DEFAULT_VARIANT, CANDIDATE_VARIANT } from '~/experimentation/constants';
import * as experimentUtils from '~/experimentation/utils'; import * as experimentUtils from '~/experimentation/utils';
const TEST_KEY = 'abc';
describe('experiment Utilities', () => { describe('experiment Utilities', () => {
const oldGon = window.gon; const TEST_KEY = 'abc';
afterEach(() => {
window.gon = oldGon;
});
describe('getExperimentData', () => { describe('getExperimentData', () => {
it.each` describe.each`
gon | input | output gon | input | output
${{ experiment: { [TEST_KEY]: '_data_' } }} | ${[TEST_KEY]} | ${'_data_'} ${[TEST_KEY, '_data_']} | ${[TEST_KEY]} | ${{ variant: '_data_' }}
${{}} | ${[TEST_KEY]} | ${undefined} ${[]} | ${[TEST_KEY]} | ${undefined}
`('with input=$input and gon=$gon, returns $output', ({ gon, input, output }) => { `('with input=$input and gon=$gon', ({ gon, input, output }) => {
window.gon = gon; assignGitlabExperiment(...gon);
expect(experimentUtils.getExperimentData(...input)).toEqual(output); it(`returns ${output}`, () => {
expect(experimentUtils.getExperimentData(...input)).toEqual(output);
});
}); });
}); });
describe('isExperimentVariant', () => { describe('isExperimentVariant', () => {
it.each` describe.each`
gon | input | output gon | input | output
${{ experiment: { [TEST_KEY]: { variant: 'control' } } }} | ${[TEST_KEY, 'control']} | ${true} ${[TEST_KEY, DEFAULT_VARIANT]} | ${[TEST_KEY, DEFAULT_VARIANT]} | ${true}
${{ experiment: { [TEST_KEY]: { variant: '_variant_name' } } }} | ${[TEST_KEY, '_variant_name']} | ${true} ${[TEST_KEY, '_variant_name']} | ${[TEST_KEY, '_variant_name']} | ${true}
${{ experiment: { [TEST_KEY]: { variant: '_variant_name' } } }} | ${[TEST_KEY, '_bogus_name']} | ${false} ${[TEST_KEY, '_variant_name']} | ${[TEST_KEY, '_bogus_name']} | ${false}
${{ experiment: { [TEST_KEY]: { variant: '_variant_name' } } }} | ${['boguskey', '_variant_name']} | ${false} ${[TEST_KEY, '_variant_name']} | ${['boguskey', '_variant_name']} | ${false}
${{}} | ${[TEST_KEY, '_variant_name']} | ${false} ${[]} | ${[TEST_KEY, '_variant_name']} | ${false}
`('with input=$input and gon=$gon, returns $output', ({ gon, input, output }) => { `('with input=$input and gon=$gon', ({ gon, input, output }) => {
window.gon = gon; assignGitlabExperiment(...gon);
it(`returns ${output}`, () => {
expect(experimentUtils.isExperimentVariant(...input)).toEqual(output);
});
});
});
describe('experiment', () => {
const controlSpy = jest.fn();
const candidateSpy = jest.fn();
const getUpStandUpSpy = jest.fn();
const variants = {
use: controlSpy,
try: candidateSpy,
get_up_stand_up: getUpStandUpSpy,
};
describe('when there is no experiment data', () => {
it('calls control variant', () => {
experimentUtils.experiment('marley', variants);
expect(controlSpy).toHaveBeenCalled();
});
});
describe('when experiment variant is "control"', () => {
assignGitlabExperiment('marley', DEFAULT_VARIANT);
it('calls the control variant', () => {
experimentUtils.experiment('marley', variants);
expect(controlSpy).toHaveBeenCalled();
});
});
describe('when experiment variant is "candidate"', () => {
assignGitlabExperiment('marley', CANDIDATE_VARIANT);
it('calls the candidate variant', () => {
experimentUtils.experiment('marley', variants);
expect(candidateSpy).toHaveBeenCalled();
});
});
describe('when experiment variant is "get_up_stand_up"', () => {
assignGitlabExperiment('marley', 'get_up_stand_up');
expect(experimentUtils.isExperimentVariant(...input)).toEqual(output); it('calls the get-up-stand-up variant', () => {
experimentUtils.experiment('marley', variants);
expect(getUpStandUpSpy).toHaveBeenCalled();
});
}); });
}); });
describe('getExperimentVariant', () => { describe('getExperimentVariant', () => {
it.each` it.each`
gon | input | output gon | input | output
${{ experiment: { [TEST_KEY]: { variant: 'control' } } }} | ${[TEST_KEY]} | ${'control'} ${{ experiment: { [TEST_KEY]: { variant: DEFAULT_VARIANT } } }} | ${[TEST_KEY]} | ${DEFAULT_VARIANT}
${{ experiment: { [TEST_KEY]: { variant: 'candidate' } } }} | ${[TEST_KEY]} | ${'candidate'} ${{ experiment: { [TEST_KEY]: { variant: CANDIDATE_VARIANT } } }} | ${[TEST_KEY]} | ${CANDIDATE_VARIANT}
${{}} | ${[TEST_KEY]} | ${DEFAULT_VARIANT} ${{}} | ${[TEST_KEY]} | ${DEFAULT_VARIANT}
`('with input=$input and gon=$gon, returns $output', ({ gon, input, output }) => { `('with input=$input and gon=$gon, returns $output', ({ gon, input, output }) => {
window.gon = gon; window.gon = gon;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment