| <!DOCTYPE html> |
| <!-- |
| Copyright 2017 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> |
| <title>cr-tryjob-picker tests</title> |
| |
| <script src="../node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script> |
| <script src="../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script> |
| <script src="../node_modules/web-component-tester/browser.js"></script> |
| |
| <test-fixture id="basic"> |
| <template> |
| <cr-tryjob-picker></cr-tryjob-picker> |
| </template> |
| </test-fixture> |
| |
| <script type="module"> |
| import './common-test-setup.js'; |
| import {assertRejects} from './test-util.js'; |
| import { |
| BuildbucketV2Client, |
| makeBuildRequests, |
| } from '../src/main/resources/static/buildbucket-client.js'; |
| import { |
| getNewOperationId, |
| } from '../src/main/resources/static/buildbucket-utils.js'; |
| import '../src/main/resources/static/cr-tryjob-picker.js'; |
| |
| suite('cr-tryjob-picker basic tests', () => { |
| let sandbox; |
| let element; |
| let closeFired = false; |
| |
| setup(() => { |
| element = fixture('basic'); |
| Object.assign(element, { |
| change: { |
| owner: {email: 'jane@example.com'}, |
| _number: 1, |
| }, |
| revision: {_number: 1}, |
| pluginConfig: { |
| gitHost: 'example.googlesource.com', |
| }, |
| }); |
| |
| closeFired = false; |
| element.addEventListener('close', (e) => { |
| closeFired = true; |
| }); |
| |
| sandbox = sandbox = sinon.sandbox.create(); |
| sandbox.stub(window, 'alert'); |
| |
| sandbox.stub(BuildbucketV2Client.prototype, 'listBuilders', |
| ({project, bucket, pageToken}) => { |
| assert.equal(bucket, 'try'); |
| const response = {}; |
| if (project == 'internal' && !pageToken) { |
| return Promise.reject('404'); |
| } else if (project === 'v8' && !pageToken) { |
| response.builders = [{id: {project, bucket, builder: 'linux'}}]; |
| } else if (project === 'chromium' && !pageToken) { |
| response.builders = [{id: {project, bucket, builder: 'linux'}}]; |
| response.nextPageToken = 'next'; |
| } else if (project === 'chromium' && pageToken === 'next') { |
| response.builders = [{id: {project, bucket, builder: 'windows'}}]; |
| } else { |
| assert.fail(`Unexpected request: ${{project, bucket, pageToken}}`); |
| } |
| return Promise.resolve(response); |
| }); |
| }); |
| |
| teardown(() => { |
| sandbox.restore(); |
| }); |
| |
| test('bucket filter function filters builders', () => { |
| let fn = element._computeBucketFilterFn(s => true); |
| assert.isTrue(fn({ |
| builders: ['blerp', 'GERP'], |
| })); |
| |
| fn = element._computeBucketFilterFn(s => /gerp/.test(s)); |
| assert.isTrue(fn({ |
| builders: ['blerp', 'gerp'], |
| })); |
| assert.isTrue(fn({ |
| builders: ['gerp'], |
| })); |
| assert.isFalse(fn({ |
| builders: ['blerp'], |
| })); |
| }); |
| |
| test('filter compilation with literal string', () => { |
| element._filter = 'abc'; |
| assert.isTrue(element._matchesFilter('abc')); |
| assert.isFalse(element._matchesFilter('a')); |
| assert.equal(element._filterClass, ''); |
| }); |
| |
| test('filter compilation with wildcard dot', () => { |
| element._filter = 'a.c'; |
| assert.isTrue(element._matchesFilter('abc')); |
| assert.isTrue(element._matchesFilter('adc')); |
| assert.isFalse(element._matchesFilter('a')); |
| assert.equal(element._filterClass, ''); |
| }); |
| |
| test('filter compilation with optional part, parens', () => { |
| element._filter = 'a(b)c'; |
| assert.isTrue(element._matchesFilter('abc')); |
| assert.isFalse(element._matchesFilter('adc')); |
| assert.isFalse(element._matchesFilter('a')); |
| assert.equal(element._filterClass, ''); |
| }); |
| |
| test('filter compilation with an invalid expression', () => { |
| element._filter = 'abc)'; |
| assert.isFalse(element._matchesFilter('abc')); |
| assert.isFalse(element._matchesFilter('a')); |
| assert.equal(element._filterClass, 'error'); |
| }); |
| |
| test('_selectedBuilders updated on checkbox change', () => { |
| const addButton = element.shadowRoot.querySelector('gr-button[primary]'); |
| const el = document.createElement('input'); |
| el.type = 'checkbox'; |
| el.setAttribute('data-project', 'proj.foo'); |
| el.setAttribute('data-bucket', 'bucket.bar'); |
| el.value = 'builder.baz'; |
| el.checked = true; |
| assert.equal(Object.keys(element._selectedBuilders).length, 0); |
| element._handleCheckboxChange({target: el}); |
| assert.deepEqual( |
| element._selectedBuilders, |
| { |
| 'proj##foo/bucket##bar/builder##baz': { |
| project: 'proj.foo', |
| bucket: 'bucket.bar', |
| builder: 'builder.baz', |
| }, |
| }); |
| assert.equal(Object.keys(element._selectedBuilders).length, 1); |
| assert.isTrue( |
| element._computeChecked('proj.foo', 'bucket.bar', 'builder.baz')); |
| assert.isFalse(addButton.hasAttribute('disabled')); |
| }); |
| |
| test('_computeBuckets merges builders', async () => { |
| // The two groups of builders that are merged are from the |
| // config (passed to _computeBuckets) and from getBuilders. |
| // In this test, the return value of getBuilders is set in |
| // the setup method above. |
| const buckets = await element._computeBuckets([ |
| { |
| name: 'luci.chromium.try', |
| builders: ['extra'], |
| }, |
| ]); |
| assert.deepEqual(buckets, [ |
| { |
| project: 'chromium', |
| bucket: 'try', |
| builders: ['extra', 'linux', 'windows'], |
| } |
| ]); |
| }); |
| |
| test('_computeBuckets ignores errors when listing builders', async () => { |
| sandbox.stub(window.console, 'error'); |
| await element._bucketsUpdating; |
| |
| element._pluginConfigChanged({ |
| buckets: [ |
| {name: 'luci.v8.try'}, |
| {name: 'luci.internal.try'}, |
| ], |
| }); |
| await element._bucketsUpdating; |
| assert.deepEqual( |
| element._buckets, |
| [ |
| {project: 'v8', bucket: 'try', builders: ['linux']}, |
| {project: 'internal', bucket: 'try', builders: []}, |
| ]); |
| }); |
| |
| test('_pluginConfigChanged called twice, second config wins', async () => { |
| await element._bucketsUpdating; |
| |
| element._pluginConfigChanged({ |
| buckets: [{ |
| name: 'luci.chromium.try', |
| }], |
| }); |
| element._pluginConfigChanged({ |
| buckets: [{ |
| name: 'luci.v8.try', |
| }], |
| }); |
| await element._bucketsUpdating; |
| assert.deepEqual( |
| element._buckets, |
| [{project: 'v8', bucket: 'try', builders: ['linux']}]); |
| }); |
| |
| test('add button is disabled when no builds are selected', async () => { |
| element.pluginConfig = { |
| buckets: [{ |
| name: 'luci.chromium.try', |
| builders: ['builder'], |
| }], |
| }; |
| await element._bucketsUpdating; |
| flushAsynchronousOperations(); |
| const addButton = element.shadowRoot.querySelector('gr-button[primary]'); |
| assert.isTrue(addButton.hasAttribute('disabled')); |
| const checkbox = element.shadowRoot.querySelector('input[type="checkbox"]'); |
| assert.ok(checkbox); |
| const changePromise = new Promise((resolve) => { |
| element.addEventListener('change', resolve); |
| }); |
| checkbox.checked = true; |
| checkbox.dispatchEvent( |
| new CustomEvent('change', {bubbles: true, composed: true})); |
| await changePromise; |
| assert.isFalse(addButton.hasAttribute('disabled')); |
| }); |
| |
| test('_includeTrybots updated when bots selected', async () => { |
| let fn = (project, bucket, builder, isChecked) => { |
| const el = document.createElement('input'); |
| el.type = 'checkbox'; |
| el.setAttribute('data-project', project); |
| el.setAttribute('data-bucket', bucket); |
| el.value = builder; |
| el.checked = isChecked; |
| return el; |
| }; |
| |
| // Check one builder. |
| const el1 = fn('proj.foo', 'bucket.bar', 'builder.baz', true); |
| assert.equal(element._includeTrybots, ''); |
| element._handleCheckboxChange({target: el1}); |
| assert.equal( |
| element._includeTrybots, 'luci.proj.foo.bucket.bar:builder.baz'); |
| |
| // Uncheck the builder. |
| el1.checked = false; |
| element._handleCheckboxChange({target: el1}); |
| assert.equal(element._includeTrybots, ''); |
| |
| // Check two builders. |
| el1.checked = true; |
| const el2 = fn('proj.foo2', 'bucket.bar2', 'builder.baz2', true); |
| element._handleCheckboxChange({target: el1}); |
| element._handleCheckboxChange({target: el2}); |
| assert.equal( |
| element._includeTrybots, 'luci.proj.foo.bucket.bar:builder.baz;' + |
| 'luci.proj.foo2.bucket.bar2:builder.baz2'); |
| |
| // Uncheck one builder. |
| el1.checked = false; |
| element._handleCheckboxChange({target: el1}); |
| assert.equal( |
| element._includeTrybots, 'luci.proj.foo2.bucket.bar2:builder.baz2'); |
| |
| // Uncheck the second builder. |
| el2.checked = false; |
| element._handleCheckboxChange({target: el2}); |
| assert.equal(element._includeTrybots, ''); |
| }); |
| |
| test('on successful scheduling', async () => { |
| element._clientOperationId = 'opid'; |
| element._selectedBuilders = { |
| 'chromium/try/linux-rel': { |
| project: 'chromium', |
| bucket: 'try', |
| builder: 'linux-rel', |
| }, |
| }; |
| sandbox.stub(BuildbucketV2Client.prototype, 'batch').returns({}); |
| await element._onAddTap(); |
| assert.isTrue(closeFired); |
| assert.isFalse(element.disabled); |
| assert.deepEqual(element._selectedBuilders, {}); |
| assert.isNull(element._clientOperationId); |
| }); |
| |
| test('on HTTP request error', async () => { |
| sandbox.stub(BuildbucketV2Client.prototype, 'batch') |
| .returns(Promise.reject(new Error('no'))); |
| const selectedBuilders = { |
| 'chromium/try/linux-rel': { |
| project: 'chromium', |
| bucket: 'try', |
| builder: 'linux-rel', |
| }, |
| }; |
| element._selectedBuilders = Object.assign({}, selectedBuilders); |
| element._clientOperationId = 'opid'; |
| await assertRejects(element._onAddTap(), 'no'); |
| assert.isFalse(closeFired); |
| assert.isFalse(element.disabled); |
| assert.deepEqual(element._selectedBuilders, selectedBuilders); |
| assert.equal(element._clientOperationId, 'opid'); |
| }); |
| |
| test('_onAddTap rejects on build request error', async () => { |
| const result = {responses: [{error: {message: 'no'}}]}; |
| sandbox.stub(BuildbucketV2Client.prototype, 'batch') |
| .returns(Promise.resolve(result)); |
| const selectedBuilders = { |
| 'chromium/try/linux-rel': { |
| project: 'chromium', |
| bucket: 'try', |
| builder: 'linux-rel', |
| }, |
| }; |
| element._selectedBuilders = Object.assign({}, selectedBuilders); |
| element._clientOperationId = 'opid'; |
| // _onTapAdd rejects, which is handled by the caller. |
| // The picker remains open, and the client operation ID is unchanged |
| // in case the caller wants to try again. |
| await assertRejects(element._onAddTap(), 'no'); |
| assert.isFalse(closeFired); |
| assert.isFalse(element.disabled); |
| assert.deepEqual(element._selectedBuilders, selectedBuilders); |
| assert.equal(element._clientOperationId, 'opid'); |
| }); |
| }); |
| </script> |