[gold] Port edit-ignore-rule-sk to TypeScript.
Bug: skia:10246
Change-Id: Id58ce9c01c2bc75bda9757d1e042ff13c8112fff
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/401223
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk-demo.js b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk-demo.js
deleted file mode 100644
index 23d53a4..0000000
--- a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk-demo.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import './index';
-import { $$ } from 'common-sk/modules/dom';
-import { manyParams } from '../shared_demo_data';
-
-Date.now = () => Date.parse('2020-02-01T00:00:00Z');
-
-function newEditIgnoreRule(parentSelector, query = '', expires = '', note = '') {
- const ele = document.createElement('edit-ignore-rule-sk');
- ele.paramset = manyParams;
- ele.query = query;
- ele.expires = expires;
- ele.note = note;
- $$(parentSelector).appendChild(ele);
-}
-
-newEditIgnoreRule('#empty');
-newEditIgnoreRule('#filled',
- 'alpha_type=Opaque&compiler=GCC&cpu_or_gpu_value=Adreno540&cpu_or_gpu_value=GTX660&'
- + 'name=01_original.jpg_0.333&source_options=codec_animated_kNonNative_unpremul',
- '2020-02-03T00:00:00Z', 'this is my note');
-$$('#filled query-sk .selection div:nth-child(1)').click();
-newEditIgnoreRule('#missing');
-$$('#missing edit-ignore-rule-sk').verifyFields();
-
-newEditIgnoreRule('#partial_custom_values');
-$$('#partial_custom_values input.custom_key').value = 'oops';
-$$('#partial_custom_values button.add_custom').click();
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk-demo.ts b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk-demo.ts
new file mode 100644
index 0000000..24e9df5
--- /dev/null
+++ b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk-demo.ts
@@ -0,0 +1,40 @@
+import './index';
+import { $$ } from 'common-sk/modules/dom';
+import { manyParams } from '../shared_demo_data';
+import { EditIgnoreRuleSk } from './edit-ignore-rule-sk';
+import { EditIgnoreRuleSkPO } from './edit-ignore-rule-sk_po';
+
+Date.now = () => Date.parse('2020-02-01T00:00:00Z');
+
+function newEditIgnoreRule(
+ parentSelector: string,
+ query = '',
+ expires = '',
+ note = ''): {el: EditIgnoreRuleSk, po: EditIgnoreRuleSkPO} {
+ const el = new EditIgnoreRuleSk();
+ el.paramset = manyParams;
+ el.query = query;
+ el.expires = expires;
+ el.note = note;
+ $$(parentSelector)!.appendChild(el);
+ return {el: el, po: new EditIgnoreRuleSkPO(el)};
+}
+
+async function populate() {
+ newEditIgnoreRule('#empty');
+
+ const {po: filledPO} = newEditIgnoreRule('#filled',
+ 'alpha_type=Opaque&compiler=GCC&cpu_or_gpu_value=Adreno540&cpu_or_gpu_value=GTX660&'
+ + 'name=01_original.jpg_0.333&source_options=codec_animated_kNonNative_unpremul',
+ '2020-02-03T00:00:00Z', 'this is my note');
+ await (await filledPO.getQuerySkPO()).clickKey('alpha_type');
+
+ const {el: missing} = newEditIgnoreRule('#missing');
+ missing.verifyFields();
+
+ const {po: partialCustomValuesPO} = newEditIgnoreRule('#partial_custom_values');
+ await partialCustomValuesPO.setCustomKey('oops');
+ await partialCustomValuesPO.clickAddCustomParamBtn();
+}
+
+populate();
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk.js b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk.js
deleted file mode 100644
index f40a7cb..0000000
--- a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk.js
+++ /dev/null
@@ -1,181 +0,0 @@
-/**
- * @module modules/edit-ignore-rule-sk
- * @description <h2><code>edit-ignore-rule-sk</code></h2>
- *
- * The edit-ignore-rule-sk element shows the pieces of a Gold ignore rule and allows for the
- * modification of them.
- *
- * TODO(kjlubick) Add client-side validation of expires values.
- */
-
-import { $$ } from 'common-sk/modules/dom';
-import { define } from 'elements-sk/define';
-import { html } from 'lit-html';
-import { diffDate } from 'common-sk/modules/human';
-import { ElementSk } from '../../../infra-sk/modules/ElementSk';
-import { humanReadableQuery } from '../common';
-
-import '../../../infra-sk/modules/query-sk';
-
-const template = (ele) => html`
- <div class=columns>
- <label for=expires>Expires in</label>
- <input placeholder="(e.g. 2w, 4h)" id=expires value=${ele._expiresText}>
- </div>
-
- <div class=columns>
- <textarea placeholder="Enter a note, e.g 'skia:1234'" id=note>${ele._note}</textarea>
- <div class=query>${humanReadableQuery(ele.query)}</div>
- </div>
-
- <query-sk .paramset=${ele.paramset} .current_query=${ele.query} hide_invert hide_regex
- @query-change=${ele._queryChanged}></query-sk>
-
- <div>
- <input class=custom_key placeholder="specify a key">
- <input class=custom_value placeholder="specify a value">
- <button class=add_custom @click=${ele._addCustomParam}
- title="Add a custom key/value pair to ignore. For example, if adding a new test/corpus and you
- want to avoid spurious comments about untriaged digests, use this to add a rule before the
- CL lands.">
- Add Custom Param
- </button>
- </div>
-
- <div class=error ?hidden=${!ele._errMsg}>${ele._errMsg}</div>
-`;
-
-
-define('edit-ignore-rule-sk', class extends ElementSk {
- constructor() {
- super(template);
- this._paramset = {};
- this._query = '';
- this._note = '';
- this._expiresText = '';
- this._errMsg = '';
- }
-
- connectedCallback() {
- super.connectedCallback();
- this._render();
- }
-
- /**
- * @prop paramset {Object} A map of String -> Array<String> containing the available key/value
- * pairs from which ignore rules may be built. For example, {'os': ['linux', 'windows']}.
- */
- get paramset() { return this._paramset; }
-
- set paramset(p) {
- this._paramset = p;
- this._render();
- }
-
- /**
- * @prop query {String} A URL-encoded string containing the selected query. For example,
- * 'alpha=beta&mind%20the_gap=space'.
- */
- get query() { return this._query; }
-
- set query(q) {
- this._query = q;
- this._render();
- }
-
- /**
- * @prop expires {String} The human readable shorthand for a time duration (e.g. '2w'). If set
- * with a date, it will be converted into shorthand notation when displayed to the user.
- * This time duration represents how long until the ignore rule "expires", i.e. when it
- * should be re-evaluated if it is needed still.
- */
- get expires() {
- // Note, this is a string like 2w, 3h - it will be parsed server-side.
- return $$('#expires', this).value;
- }
-
- set expires(d) {
- // We are given a date string, we turn it into the human readable text. There might be some
- // loss of fidelity (e.g. a time of 2 weeks minus 10 minutes gets rounded to 2w gets rounded),
- // but that's ok - the developers don't expect expiration times to be ultra precise.
- const nowMS = Date.now();
- const newMS = Date.parse(d);
- if (!newMS || newMS < nowMS) {
- this._expiresText = '';
- } else {
- this._expiresText = diffDate(d);
- }
- this._render();
- }
-
- /**
- * @prop note {String} A note, usually a comment, to accompany the ignore rule.
- */
- get note() { return $$('#note', this).value; }
-
- set note(n) {
- this._note = n;
- this._render();
- }
-
- _addCustomParam() {
- const keyInput = $$('input.custom_key', this);
- const valueInput = $$('input.custom_value', this);
-
- const key = keyInput.value;
- const value = valueInput.value;
- if (!key || !value) {
- this._errMsg = 'Must specify both a key and a value';
- this._render();
- return;
- }
- // Push the key/value to the _paramset so the query-sk can treat it like a normal value.
- const values = this._paramset[key] || [];
- values.push(value);
- this._paramset[key] = values;
- this._errMsg = '';
- // Add the selection to the query so it shows up for the user.
- const newParam = `${key}=${value}`;
- if (this._query) {
- this._query += `&${newParam}`;
- } else {
- this._query = newParam;
- }
- this._render();
- }
-
- _queryChanged(e) {
- // Stop the query-sk event from leaving this element to avoid confusing a parent element
- // with unexpected events.
- e.stopPropagation();
- this.query = e.detail.q;
- }
-
- /**
- * Resets input, outputs, and error, other than the paramset. The paramset field will likely
- * not change over the lifetime of this element.
- */
- reset() {
- this._query = '';
- this._note = '';
- this._expiresText = '';
- this._errMsg = '';
- this._render();
- }
-
- /**
- * Checks that all the required inputs (query and expires) have non-empty values. If so, it
- * returns true, otherwise, it will display an error on the element.
- * @return {boolean}
- */
- verifyFields() {
- if (this.query && this.expires) {
- this._errMsg = '';
- this._render();
- return true;
- }
- this._errMsg = 'Must specify a non-empty filter and an expiration.';
- this._render();
- return false;
- }
-});
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk.ts b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk.ts
new file mode 100644
index 0000000..72e516a
--- /dev/null
+++ b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk.ts
@@ -0,0 +1,182 @@
+/**
+ * @module modules/edit-ignore-rule-sk
+ * @description <h2><code>edit-ignore-rule-sk</code></h2>
+ *
+ * The edit-ignore-rule-sk element shows the pieces of a Gold ignore rule and allows for the
+ * modification of them.
+ *
+ * TODO(kjlubick) Add client-side validation of expires values.
+ */
+
+import { define } from 'elements-sk/define';
+import { html } from 'lit-html';
+import { diffDate } from 'common-sk/modules/human';
+import { ElementSk } from '../../../infra-sk/modules/ElementSk';
+import { humanReadableQuery } from '../common';
+import { ParamSet } from '../rpc_types';
+import { QuerySkQueryChangeEventDetail } from '../../../infra-sk/modules/query-sk/query-sk';
+
+import '../../../infra-sk/modules/query-sk';
+
+export class EditIgnoreRuleSk extends ElementSk {
+
+ private static template = (ele: EditIgnoreRuleSk) => html`
+ <div class=columns>
+ <label for=expires>Expires in</label>
+ <input placeholder="(e.g. 2w, 4h)" id=expires value=${ele._expires}>
+ </div>
+
+ <div class=columns>
+ <textarea placeholder="Enter a note, e.g 'skia:1234'" id=note>${ele._note}</textarea>
+ <div class=query>${humanReadableQuery(ele.query)}</div>
+ </div>
+
+ <query-sk .paramset=${ele.paramset} .current_query=${ele.query} hide_invert hide_regex
+ @query-change=${ele.queryChanged}></query-sk>
+
+ <div>
+ <input class=custom_key placeholder="specify a key">
+ <input class=custom_value placeholder="specify a value">
+ <button class=add_custom @click=${ele.addCustomParam}
+ title="Add a custom key/value pair to ignore. For example, if adding a new test/corpus and
+ you want to avoid spurious comments about untriaged digests, use this to add a rule
+ before the CL lands.">
+ Add Custom Param
+ </button>
+ </div>
+
+ <div class=error ?hidden=${!ele.errMsg}>${ele.errMsg}</div>
+ `;
+
+ private _paramset: ParamSet = {};
+ private _query = '';
+ private _note = '';
+ private _expires = '';
+ private errMsg = '';
+
+ constructor() {
+ super(EditIgnoreRuleSk.template);
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this._render();
+ }
+
+ /**
+ * Key/value pairs from which ignore rules may be built. For example,
+ * `{'os': ['linux', 'windows']}`.
+ */
+ get paramset(): ParamSet { return this._paramset; }
+
+ set paramset(p: ParamSet) {
+ this._paramset = p;
+ this._render();
+ }
+
+ /**
+ * A URL-encoded string containing the selected query. For example,
+ * 'alpha=beta&mind%20the_gap=space'`.
+ */
+ get query(): string { return this._query; }
+
+ set query(q: string) {
+ this._query = q;
+ this._render();
+ }
+
+ /**
+ * The human readable shorthand for a time duration (e.g. '2w'). If set with a date, it will be
+ * converted into shorthand notation when displayed to the user. This time duration represents
+ * how long until the ignore rule "expires", i.e. when it should be re-evaluated if it is needed
+ * still.
+ */
+ get expires(): string {
+ // Note, this is a string like 2w, 3h - it will be parsed server-side.
+ return this.querySelector<HTMLInputElement>('#expires')!.value;
+ }
+
+ set expires(d: string) {
+ // We are given a date string, we turn it into the human readable text. There might be some
+ // loss of fidelity (e.g. a time of 2 weeks minus 10 minutes gets rounded to 2w gets rounded),
+ // but that's ok - the developers don't expect expiration times to be ultra precise.
+ const nowMS = Date.now();
+ const newMS = Date.parse(d);
+ if (!newMS || newMS < nowMS) {
+ this._expires = '';
+ } else {
+ this._expires = diffDate(d);
+ }
+ this._render();
+ }
+
+ /** A note, usually a comment, to accompany the ignore rule. */
+ get note(): string { return this.querySelector<HTMLInputElement>('#note')!.value; }
+
+ set note(n: string) {
+ this._note = n;
+ this._render();
+ }
+
+ private addCustomParam() {
+ const keyInput = this.querySelector<HTMLInputElement>('input.custom_key')!;
+ const valueInput = this.querySelector<HTMLInputElement>('input.custom_value')!;
+
+ const key = keyInput.value;
+ const value = valueInput.value;
+ if (!key || !value) {
+ this.errMsg = 'Must specify both a key and a value.';
+ this._render();
+ return;
+ }
+ // Push the key/value to the _paramset so the query-sk can treat it like a normal value.
+ const values = this._paramset[key] || [];
+ values.push(value);
+ this._paramset[key] = values;
+ this.errMsg = '';
+ // Add the selection to the query so it shows up for the user.
+ const newParam = `${key}=${value}`;
+ if (this._query) {
+ this._query += `&${newParam}`;
+ } else {
+ this._query = newParam;
+ }
+ this._render();
+ }
+
+ private queryChanged(e: CustomEvent<QuerySkQueryChangeEventDetail>) {
+ // Stop the query-sk event from leaving this element to avoid confusing a parent element
+ // with unexpected events.
+ e.stopPropagation();
+ this.query = e.detail.q;
+ }
+
+ /**
+ * Resets input, outputs, and error, other than the paramset. The paramset field will likely
+ * not change over the lifetime of this element.
+ */
+ reset() {
+ this._query = '';
+ this._note = '';
+ this._expires = '';
+ this.errMsg = '';
+ this._render();
+ }
+
+ /**
+ * Checks that all the required inputs (query and expires) have non-empty values. If so, it
+ * returns true, otherwise, it will display an error on the element.
+ */
+ verifyFields(): boolean {
+ if (this.query && this.expires) {
+ this.errMsg = '';
+ this._render();
+ return true;
+ }
+ this.errMsg = 'Must specify a non-empty filter and an expiration.';
+ this._render();
+ return false;
+ }
+}
+
+define('edit-ignore-rule-sk', EditIgnoreRuleSk);
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_po.ts b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_po.ts
new file mode 100644
index 0000000..a8db760
--- /dev/null
+++ b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_po.ts
@@ -0,0 +1,60 @@
+import { PageObject } from '../../../infra-sk/modules/page_object/page_object';
+import { QuerySkPO } from '../../../infra-sk/modules/query-sk/query-sk_po';
+
+/** A page object for the EditIgnoreRuleSk component. */
+export class EditIgnoreRuleSkPO extends PageObject {
+ getExpires(): Promise<string> {
+ return this.selectOnePOEThenApplyFn('#expires', (poe) => poe.value);
+ }
+
+ async setExpires(value: string) {
+ await this.selectOnePOEThenApplyFn('#expires', (poe) => poe.enterValue(value));
+ }
+
+ getNote(): Promise<string> {
+ return this.selectOnePOEThenApplyFn('#note', (poe) => poe.value);
+ }
+
+ async setNote(value: string) {
+ await this.selectOnePOEThenApplyFn('#note', (poe) => poe.enterValue(value));
+ }
+
+ getCustomKey(): Promise<string> {
+ return this.selectOnePOEThenApplyFn('.custom_key', (poe) => poe.value);
+ }
+
+ async setCustomKey(value: string) {
+ await this.selectOnePOEThenApplyFn('.custom_key', (poe) => poe.enterValue(value));
+ }
+
+ getCustomValue(): Promise<string> {
+ return this.selectOnePOEThenApplyFn('.custom_value', (poe) => poe.value);
+ }
+
+ async setCustomValue(value: string) {
+ await this.selectOnePOEThenApplyFn('.custom_value', (poe) => poe.enterValue(value));
+ }
+
+ async clickAddCustomParamBtn() {
+ const btn = await this.selectOnePOE('.add_custom');
+ await btn!.click();
+ }
+
+ getQuery(): Promise<string> {
+ return this.selectOnePOEThenApplyFn('.query', (poe) => poe.innerText);
+ }
+
+ isErrorMessageVisible(): Promise<boolean> {
+ return this.selectOnePOEThenApplyFn(
+ '.error',
+ async (poe) => !(await poe.hasAttribute('hidden')));
+ }
+
+ getErrorMessage(): Promise<string> {
+ return this.selectOnePOEThenApplyFn('.error', (poe) => poe.innerText);
+ }
+
+ getQuerySkPO(): Promise<QuerySkPO> {
+ return this.selectOnePOEThenApplyFn('query-sk', async (poe) => new QuerySkPO(poe));
+ }
+}
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_test.js b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_test.js
deleted file mode 100644
index 9671099..0000000
--- a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_test.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import './index';
-import { $$ } from 'common-sk/modules/dom';
-import { setUpElementUnderTest } from '../../../infra-sk/modules/test_util';
-
-describe('edit-ignore-rule-sk', () => {
- const newInstance = setUpElementUnderTest('edit-ignore-rule-sk');
-
- // This date is arbitrary
- const fakeNow = Date.parse('2020-02-01T00:00:00Z');
- const regularNow = Date.now;
-
- let editIgnoreRuleSk;
- beforeEach(() => {
- editIgnoreRuleSk = newInstance();
- // All tests will have the paramset loaded.
- editIgnoreRuleSk.paramset = {
- alpha_type: ['Opaque', 'Premul'],
- arch: ['arm', 'arm64', 'x86', 'x86_64'],
- };
- Date.now = () => fakeNow;
- });
-
- afterEach(() => {
- Date.now = regularNow;
- });
-
- describe('inputs and outputs', () => {
- it('has no query, note or expires', () => {
- expect(editIgnoreRuleSk.query).to.equal('');
- expect(editIgnoreRuleSk.note).to.equal('');
- expect(editIgnoreRuleSk.expires).to.equal('');
- });
-
- it('reflects typed in values', () => {
- getExpiresInput(editIgnoreRuleSk).value = '2w';
- getNoteInput(editIgnoreRuleSk).value = 'this is a bug';
- expect(editIgnoreRuleSk.expires).to.equal('2w');
- expect(editIgnoreRuleSk.note).to.equal('this is a bug');
- });
-
- it('reflects interactions with the query-sk element', () => {
- // Select alpha_type key, which displays Opaque and Premul as values.
- getFirstQuerySkKey(editIgnoreRuleSk).click();
- // Select Opaque as a value
- getFirstQuerySkValue(editIgnoreRuleSk).click();
- expect(editIgnoreRuleSk.query).to.equal('alpha_type=Opaque');
- });
-
- it('converts future dates to human readable durations', () => {
- editIgnoreRuleSk.expires = '2020-02-07T06:00:00Z';
- // It is ok that the 6 hours gets rounded out.
- expect(editIgnoreRuleSk.expires).to.equal('6d');
- });
-
- it('converts past or invalid dates to nothing (requiring them to be re-input)', () => {
- editIgnoreRuleSk.expires = '2020-01-07T06:00:00Z';
- expect(editIgnoreRuleSk.expires).to.equal('');
- editIgnoreRuleSk.expires = 'invalid date';
- expect(editIgnoreRuleSk.expires).to.equal('');
- });
-
- it('can add a custom key and value', () => {
- editIgnoreRuleSk.query = 'arch=arm64';
-
- // Add a new value to an existing param
- getCustomKeyInput(editIgnoreRuleSk).value = 'arch';
- getCustomValueInput(editIgnoreRuleSk).value = 'y75';
- clickAddCustomParam(editIgnoreRuleSk);
-
- // add a brand new key and value
- getCustomKeyInput(editIgnoreRuleSk).value = 'custom';
- getCustomValueInput(editIgnoreRuleSk).value = 'value';
- clickAddCustomParam(editIgnoreRuleSk);
-
- expect(editIgnoreRuleSk.query).to.equal('arch=arm64&arch=y75&custom=value');
- // ParamSet should be mutated to have the new values
- expect(editIgnoreRuleSk.paramset.arch).to.deep.equal(['arm', 'arm64', 'x86', 'x86_64', 'y75']);
- expect(editIgnoreRuleSk.paramset.custom).to.deep.equal(['value']);
- });
- });
-
- describe('validation', () => {
- it('has the error msg hidden by default', () => {
- expect(getErrorMessage(editIgnoreRuleSk).hasAttribute('hidden')).to.be.true;
- });
-
- it('does not validate when query is empty', () => {
- editIgnoreRuleSk.query = '';
- editIgnoreRuleSk.expires = '2w';
- expect(editIgnoreRuleSk.verifyFields()).to.be.false;
- expect(getErrorMessage(editIgnoreRuleSk).hasAttribute('hidden')).to.be.false;
- });
-
- it('does not validate when expires is empty', () => {
- editIgnoreRuleSk.query = 'alpha_type=Opaque';
- editIgnoreRuleSk.expires = '';
- expect(editIgnoreRuleSk.verifyFields()).to.be.false;
- expect(getErrorMessage(editIgnoreRuleSk).hasAttribute('hidden')).to.be.false;
- });
-
- it('does not validate when both expires and query are empty', () => {
- editIgnoreRuleSk.query = '';
- editIgnoreRuleSk.expires = '';
- expect(editIgnoreRuleSk.verifyFields()).to.be.false;
- expect(getErrorMessage(editIgnoreRuleSk).hasAttribute('hidden')).to.be.false;
- });
-
- it('does passes validation when both expires and query are set', () => {
- editIgnoreRuleSk.query = 'foo=bar';
- getExpiresInput(editIgnoreRuleSk).value = '1w';
- expect(editIgnoreRuleSk.verifyFields()).to.be.true;
- expect(getErrorMessage(editIgnoreRuleSk).hasAttribute('hidden')).to.be.true;
- });
-
- it('requires both a custom key and value', () => {
- expect(editIgnoreRuleSk.query).to.equal('');
-
- getCustomKeyInput(editIgnoreRuleSk).value = '';
- getCustomValueInput(editIgnoreRuleSk).value = '';
- clickAddCustomParam(editIgnoreRuleSk);
-
- expect(editIgnoreRuleSk._errMsg).to.contain('both a key and a value');
- expect(editIgnoreRuleSk.query).to.equal('');
-
- getCustomKeyInput(editIgnoreRuleSk).value = 'custom';
- getCustomValueInput(editIgnoreRuleSk).value = '';
- clickAddCustomParam(editIgnoreRuleSk);
-
- expect(editIgnoreRuleSk._errMsg).to.contain('both a key and a value');
- expect(editIgnoreRuleSk.query).to.equal('');
-
- getCustomKeyInput(editIgnoreRuleSk).value = '';
- getCustomValueInput(editIgnoreRuleSk).value = 'value';
- clickAddCustomParam(editIgnoreRuleSk);
-
- expect(editIgnoreRuleSk._errMsg).to.contain('both a key and a value');
- expect(editIgnoreRuleSk.query).to.equal('');
- });
- });
-});
-
-const getExpiresInput = (ele) => $$('#expires', ele);
-
-const getNoteInput = (ele) => $$('#note', ele);
-
-const getCustomKeyInput = (ele) => $$('input.custom_key', ele);
-
-const getCustomValueInput = (ele) => $$('input.custom_value', ele);
-
-const getErrorMessage = (ele) => $$('.error', ele);
-
-const getFirstQuerySkKey = (ele) => $$('query-sk .selection div:nth-child(1)', ele);
-
-const getFirstQuerySkValue = (ele) => $$('query-sk #values div:nth-child(1)', ele);
-
-const clickAddCustomParam = (ele) => $$('button.add_custom', ele).click();
diff --git a/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_test.ts b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_test.ts
new file mode 100644
index 0000000..6e9fd0a
--- /dev/null
+++ b/golden/modules/edit-ignore-rule-sk/edit-ignore-rule-sk_test.ts
@@ -0,0 +1,145 @@
+import './index';
+import { setUpElementUnderTest } from '../../../infra-sk/modules/test_util';
+import { EditIgnoreRuleSk } from './edit-ignore-rule-sk';
+import { EditIgnoreRuleSkPO } from './edit-ignore-rule-sk_po';
+import { expect } from 'chai';
+
+describe('edit-ignore-rule-sk', () => {
+ const newInstance = setUpElementUnderTest<EditIgnoreRuleSk>('edit-ignore-rule-sk');
+
+ // This date is arbitrary
+ const fakeNow = Date.parse('2020-02-01T00:00:00Z');
+ const regularNow = Date.now;
+
+ let editIgnoreRuleSk: EditIgnoreRuleSk;
+ let editIgnoreRuleSkPO: EditIgnoreRuleSkPO;
+
+ beforeEach(() => {
+ editIgnoreRuleSk = newInstance();
+ // All tests will have the paramset loaded.
+ editIgnoreRuleSk.paramset = {
+ alpha_type: ['Opaque', 'Premul'],
+ arch: ['arm', 'arm64', 'x86', 'x86_64'],
+ };
+ Date.now = () => fakeNow;
+ editIgnoreRuleSkPO = new EditIgnoreRuleSkPO(editIgnoreRuleSk);
+ });
+
+ afterEach(() => {
+ Date.now = regularNow;
+ });
+
+ describe('inputs and outputs', () => {
+ it('has no query, note or expires', () => {
+ expect(editIgnoreRuleSk.query).to.equal('');
+ expect(editIgnoreRuleSk.note).to.equal('');
+ expect(editIgnoreRuleSk.expires).to.equal('');
+ });
+
+ it('reflects typed in values', async () => {
+ await editIgnoreRuleSkPO.setExpires('2w');
+ await editIgnoreRuleSkPO.setNote('this is a bug');
+ expect(editIgnoreRuleSk.expires).to.equal('2w');
+ expect(editIgnoreRuleSk.note).to.equal('this is a bug');
+ });
+
+ it('reflects interactions with the query-sk element', async () => {
+ const querySkPO = await editIgnoreRuleSkPO.getQuerySkPO();
+ await querySkPO.clickKey('alpha_type');
+ await querySkPO.clickValue('Opaque');
+ expect(editIgnoreRuleSk.query).to.equal('alpha_type=Opaque');
+ });
+
+ it('converts future dates to human readable durations', () => {
+ editIgnoreRuleSk.expires = '2020-02-07T06:00:00Z';
+ // It is ok that the 6 hours gets rounded out.
+ expect(editIgnoreRuleSk.expires).to.equal('6d');
+ });
+
+ it('converts past or invalid dates to nothing (requiring them to be re-input)', () => {
+ editIgnoreRuleSk.expires = '2020-01-07T06:00:00Z';
+ expect(editIgnoreRuleSk.expires).to.equal('');
+ editIgnoreRuleSk.expires = 'invalid date';
+ expect(editIgnoreRuleSk.expires).to.equal('');
+ });
+
+ it('can add a custom key and value', async () => {
+ editIgnoreRuleSk.query = 'arch=arm64';
+
+ // Add a new value to an existing param
+ await editIgnoreRuleSkPO.setCustomKey('arch');
+ await editIgnoreRuleSkPO.setCustomValue('y75');
+ await editIgnoreRuleSkPO.clickAddCustomParamBtn();
+
+ // add a brand new key and value
+ await editIgnoreRuleSkPO.setCustomKey('custom');
+ await editIgnoreRuleSkPO.setCustomValue('value');
+ await editIgnoreRuleSkPO.clickAddCustomParamBtn();
+
+ expect(editIgnoreRuleSk.query).to.equal('arch=arm64&arch=y75&custom=value');
+ // ParamSet should be mutated to have the new values
+ expect(editIgnoreRuleSk.paramset.arch)
+ .to.deep.equal(['arm', 'arm64', 'x86', 'x86_64', 'y75']);
+ expect(editIgnoreRuleSk.paramset.custom).to.deep.equal(['value']);
+ });
+ });
+
+ describe('validation', () => {
+ it('has the error msg hidden by default', async () => {
+ expect(await editIgnoreRuleSkPO.isErrorMessageVisible()).to.be.false;
+ });
+
+ it('does not validate when query is empty', async () => {
+ editIgnoreRuleSk.query = '';
+ editIgnoreRuleSk.expires = '2w';
+ expect(editIgnoreRuleSk.verifyFields()).to.be.false;
+ expect(await editIgnoreRuleSkPO.isErrorMessageVisible()).to.be.true;
+ });
+
+ it('does not validate when expires is empty', async () => {
+ editIgnoreRuleSk.query = 'alpha_type=Opaque';
+ editIgnoreRuleSk.expires = '';
+ expect(editIgnoreRuleSk.verifyFields()).to.be.false;
+ expect(await editIgnoreRuleSkPO.isErrorMessageVisible()).to.be.true;
+ });
+
+ it('does not validate when both expires and query are empty', async () => {
+ editIgnoreRuleSk.query = '';
+ editIgnoreRuleSk.expires = '';
+ expect(editIgnoreRuleSk.verifyFields()).to.be.false;
+ expect(await editIgnoreRuleSkPO.isErrorMessageVisible()).to.be.true;
+ });
+
+ it('does passes validation when both expires and query are set', async () => {
+ editIgnoreRuleSk.query = 'foo=bar';
+ await editIgnoreRuleSkPO.setExpires('1w');
+ expect(editIgnoreRuleSk.verifyFields()).to.be.true;
+ expect(await editIgnoreRuleSkPO.isErrorMessageVisible()).to.be.false;
+ });
+
+ it('requires both a custom key and value', async () => {
+ expect(editIgnoreRuleSk.query).to.equal('');
+
+ await editIgnoreRuleSkPO.setCustomKey('');
+ await editIgnoreRuleSkPO.setCustomValue('');
+ await editIgnoreRuleSkPO.clickAddCustomParamBtn();
+
+ expect(await editIgnoreRuleSkPO.getErrorMessage()).to.contain('both a key and a value');
+ expect(editIgnoreRuleSk.query).to.equal('');
+
+ await editIgnoreRuleSkPO.setCustomKey('custom');
+ await editIgnoreRuleSkPO.setCustomValue('');
+ await editIgnoreRuleSkPO.clickAddCustomParamBtn();
+
+ expect(await editIgnoreRuleSkPO.getErrorMessage()).to.contain('both a key and a value');
+ expect(editIgnoreRuleSk.query).to.equal('');
+
+ await editIgnoreRuleSkPO.setCustomKey('');
+ await editIgnoreRuleSkPO.setCustomValue('value');
+ await editIgnoreRuleSkPO.clickAddCustomParamBtn();
+
+ expect(await editIgnoreRuleSkPO.getErrorMessage()).to.contain('both a key and a value');
+ expect(editIgnoreRuleSk.query).to.equal('');
+ });
+ });
+});
diff --git a/golden/modules/edit-ignore-rule-sk/index.js b/golden/modules/edit-ignore-rule-sk/index.ts
similarity index 100%
rename from golden/modules/edit-ignore-rule-sk/index.js
rename to golden/modules/edit-ignore-rule-sk/index.ts