mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-03 20:17:59 +00:00 
			
		
		
		
	UI: address flaky auth-jwt and control group tests (#28297)
* address flaky auth-jwt test * refactor control group success test
This commit is contained in:
		@@ -9,7 +9,7 @@ export const AUTH_FORM = {
 | 
				
			|||||||
  tabs: (method: string) => (method ? `[data-test-auth-method="${method}"]` : '[data-test-auth-method]'),
 | 
					  tabs: (method: string) => (method ? `[data-test-auth-method="${method}"]` : '[data-test-auth-method]'),
 | 
				
			||||||
  description: '[data-test-description]',
 | 
					  description: '[data-test-description]',
 | 
				
			||||||
  roleInput: '[data-test-role]',
 | 
					  roleInput: '[data-test-role]',
 | 
				
			||||||
  input: (item: string) => `[data-test-${item}]`, // i.e. role, token, password or username
 | 
					  input: (item: string) => `[data-test-${item}]`, // i.e. jwt, role, token, password or username
 | 
				
			||||||
  mountPathInput: '[data-test-auth-form-mount-path]',
 | 
					  mountPathInput: '[data-test-auth-form-mount-path]',
 | 
				
			||||||
  moreOptions: '[data-test-auth-form-options-toggle]',
 | 
					  moreOptions: '[data-test-auth-form-options-toggle]',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,16 +6,17 @@
 | 
				
			|||||||
import { _cancelTimers as cancelTimers } from '@ember/runloop';
 | 
					import { _cancelTimers as cancelTimers } from '@ember/runloop';
 | 
				
			||||||
import { module, test } from 'qunit';
 | 
					import { module, test } from 'qunit';
 | 
				
			||||||
import { setupRenderingTest } from 'ember-qunit';
 | 
					import { setupRenderingTest } from 'ember-qunit';
 | 
				
			||||||
import { render, settled, waitUntil } from '@ember/test-helpers';
 | 
					import { fillIn, render, settled, waitUntil } from '@ember/test-helpers';
 | 
				
			||||||
import hbs from 'htmlbars-inline-precompile';
 | 
					import hbs from 'htmlbars-inline-precompile';
 | 
				
			||||||
import sinon from 'sinon';
 | 
					import sinon from 'sinon';
 | 
				
			||||||
import { resolve } from 'rsvp';
 | 
					import { resolve } from 'rsvp';
 | 
				
			||||||
import { create } from 'ember-cli-page-object';
 | 
					import { create } from 'ember-cli-page-object';
 | 
				
			||||||
import form from '../../pages/components/auth-jwt';
 | 
					import form from '../../pages/components/auth-jwt';
 | 
				
			||||||
import { ERROR_WINDOW_CLOSED, ERROR_MISSING_PARAMS, ERROR_JWT_LOGIN } from 'vault/components/auth-jwt';
 | 
					import { ERROR_WINDOW_CLOSED, ERROR_MISSING_PARAMS, ERROR_JWT_LOGIN } from 'vault/components/auth-jwt';
 | 
				
			||||||
import { fakeWindow, buildMessage } from '../../helpers/oidc-window-stub';
 | 
					import { fakeWindow, buildMessage } from 'vault/tests/helpers/oidc-window-stub';
 | 
				
			||||||
import { setupMirage } from 'ember-cli-mirage/test-support';
 | 
					import { setupMirage } from 'ember-cli-mirage/test-support';
 | 
				
			||||||
import { overrideResponse } from 'vault/tests/helpers/stubs';
 | 
					import { overrideResponse } from 'vault/tests/helpers/stubs';
 | 
				
			||||||
 | 
					import { AUTH_FORM } from 'vault/tests/helpers/auth/auth-form-selectors';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const component = create(form);
 | 
					const component = create(form);
 | 
				
			||||||
const windows = [];
 | 
					const windows = [];
 | 
				
			||||||
@@ -33,12 +34,6 @@ fakeWindow.reopen({
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const OIDC_AUTH_RESPONSE = {
 | 
					 | 
				
			||||||
  auth: {
 | 
					 | 
				
			||||||
    client_token: 'token',
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const renderIt = async (context, path = 'jwt') => {
 | 
					const renderIt = async (context, path = 'jwt') => {
 | 
				
			||||||
  const handler = (data, e) => {
 | 
					  const handler = (data, e) => {
 | 
				
			||||||
    if (e && e.preventDefault) e.preventDefault();
 | 
					    if (e && e.preventDefault) e.preventDefault();
 | 
				
			||||||
@@ -75,11 +70,11 @@ module('Integration | Component | auth jwt', function (hooks) {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.server.get('/auth/:path/oidc/callback', function () {
 | 
					    this.server.get('/auth/:path/oidc/callback', function () {
 | 
				
			||||||
      return OIDC_AUTH_RESPONSE;
 | 
					      return { auth: { client_token: 'token' } };
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.server.post('/auth/:path/oidc/auth_url', (_, request) => {
 | 
					    this.server.post('/auth/:path/oidc/auth_url', (_, request) => {
 | 
				
			||||||
      const { role } = JSON.parse(request.requestBody);
 | 
					      const { role } = JSON.parse(request.requestBody);
 | 
				
			||||||
      if (['test', 'bar'].includes(role)) {
 | 
					      if (['okta', 'test', 'bar'].includes(role)) {
 | 
				
			||||||
        const auth_url = role === 'test' ? 'http://example.com' : role === 'okta' ? 'http://okta.com' : '';
 | 
					        const auth_url = role === 'test' ? 'http://example.com' : role === 'okta' ? 'http://okta.com' : '';
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
          data: { auth_url },
 | 
					          data: { auth_url },
 | 
				
			||||||
@@ -127,35 +122,46 @@ module('Integration | Component | auth jwt', function (hooks) {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('oidc: test role: it renders', async function (assert) {
 | 
					  test('oidc: test role: it renders', async function (assert) {
 | 
				
			||||||
 | 
					    // setting the path also fires off a request to auth_url but this happens inconsistently in tests
 | 
				
			||||||
 | 
					    // setting here so it doesn't affect the postCount because it's not relevant to what's being tested
 | 
				
			||||||
 | 
					    this.set('selectedAuthPath', 'foo');
 | 
				
			||||||
    let postCount = 0;
 | 
					    let postCount = 0;
 | 
				
			||||||
    this.server.post('/auth/:path/oidc/auth_url', (_, request) => {
 | 
					    this.server.post('/auth/:path/oidc/auth_url', (_, request) => {
 | 
				
			||||||
      postCount++;
 | 
					      postCount++;
 | 
				
			||||||
      const { role } = JSON.parse(request.requestBody);
 | 
					      const { role } = JSON.parse(request.requestBody);
 | 
				
			||||||
      if (['test', 'okta', 'bar'].includes(role)) {
 | 
					      const auth_url = role === 'test' ? 'http://example.com' : role === 'okta' ? 'http://okta.com' : '';
 | 
				
			||||||
        const auth_url = role === 'test' ? 'http://example.com' : role === 'okta' ? 'http://okta.com' : '';
 | 
					      return {
 | 
				
			||||||
        return {
 | 
					        data: { auth_url },
 | 
				
			||||||
          data: { auth_url },
 | 
					      };
 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const errors = role === 'foo' ? ['role "foo" could not be found'] : [ERROR_JWT_LOGIN];
 | 
					 | 
				
			||||||
      return overrideResponse(400, { errors });
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    await renderIt(this);
 | 
					    await renderIt(this);
 | 
				
			||||||
    await settled();
 | 
					    await settled();
 | 
				
			||||||
    this.set('selectedAuthPath', 'foo');
 | 
					    await fillIn(AUTH_FORM.roleInput, 'test');
 | 
				
			||||||
    await component.role('test');
 | 
					    assert
 | 
				
			||||||
    await settled();
 | 
					      .dom(AUTH_FORM.input('jwt'))
 | 
				
			||||||
    assert.notOk(component.jwtPresent, 'does not show jwt input for OIDC type login');
 | 
					      .doesNotExist('does not show jwt token input if role matches OIDC login url');
 | 
				
			||||||
    assert.strictEqual(component.loginButtonText, 'Sign in with OIDC Provider');
 | 
					    assert.dom(AUTH_FORM.login).hasText('Sign in with OIDC Provider');
 | 
				
			||||||
 | 
					    await fillIn(AUTH_FORM.roleInput, 'okta');
 | 
				
			||||||
    await component.role('okta');
 | 
					 | 
				
			||||||
    // 1 for initial render, 1 for each time role changed = 3
 | 
					    // 1 for initial render, 1 for each time role changed = 3
 | 
				
			||||||
    assert.strictEqual(postCount, 3, 'fetches the auth_url when the path changes');
 | 
					    assert.strictEqual(postCount, 3, 'fetches the auth_url when the role changes');
 | 
				
			||||||
    assert.strictEqual(
 | 
					    assert.dom(AUTH_FORM.login).hasText('Sign in with Okta', 'recognizes auth methods with certain urls');
 | 
				
			||||||
      component.loginButtonText,
 | 
					  });
 | 
				
			||||||
      'Sign in with Okta',
 | 
					
 | 
				
			||||||
      'recognizes auth methods with certain urls'
 | 
					  test('oidc: it fetches auth_url when path changes', async function (assert) {
 | 
				
			||||||
    );
 | 
					    assert.expect(2);
 | 
				
			||||||
 | 
					    this.set('selectedAuthPath', 'foo');
 | 
				
			||||||
 | 
					    await renderIt(this);
 | 
				
			||||||
 | 
					    // auth_url is requested on initial render so stubbing after rendering the component
 | 
				
			||||||
 | 
					    // to test auth_url is called when the :path changes
 | 
				
			||||||
 | 
					    this.server.post('/auth/:path/oidc/auth_url', (_, request) => {
 | 
				
			||||||
 | 
					      assert.true(true, 'request is made to auth_url');
 | 
				
			||||||
 | 
					      assert.strictEqual(request?.params?.path, 'foo', 'request params are { path: foo }');
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        data: { auth_url: '' },
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.set('selectedAuthPath', 'foo');
 | 
				
			||||||
 | 
					    await settled();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('oidc: it calls window.open popup window on login', async function (assert) {
 | 
					  test('oidc: it calls window.open popup window on login', async function (assert) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,97 +3,95 @@
 | 
				
			|||||||
 * SPDX-License-Identifier: BUSL-1.1
 | 
					 * SPDX-License-Identifier: BUSL-1.1
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { later, run, _cancelTimers as cancelTimers } from '@ember/runloop';
 | 
					 | 
				
			||||||
import { resolve } from 'rsvp';
 | 
					import { resolve } from 'rsvp';
 | 
				
			||||||
import Service from '@ember/service';
 | 
					import Service from '@ember/service';
 | 
				
			||||||
import { module, test } from 'qunit';
 | 
					import { module, test } from 'qunit';
 | 
				
			||||||
import { setupRenderingTest } from 'ember-qunit';
 | 
					import { setupRenderingTest } from 'ember-qunit';
 | 
				
			||||||
import { render, settled } from '@ember/test-helpers';
 | 
					import { click, fillIn, find, render } from '@ember/test-helpers';
 | 
				
			||||||
import hbs from 'htmlbars-inline-precompile';
 | 
					import hbs from 'htmlbars-inline-precompile';
 | 
				
			||||||
import sinon from 'sinon';
 | 
					import sinon from 'sinon';
 | 
				
			||||||
import { create } from 'ember-cli-page-object';
 | 
					 | 
				
			||||||
import controlGroupSuccess from '../../pages/components/control-group-success';
 | 
					 | 
				
			||||||
import { setRunOptions } from 'ember-a11y-testing/test-support';
 | 
					import { setRunOptions } from 'ember-a11y-testing/test-support';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const component = create(controlGroupSuccess);
 | 
					const SELECTORS = {
 | 
				
			||||||
 | 
					  jsonViewer: '[data-test-json-viewer]',
 | 
				
			||||||
const controlGroupService = Service.extend({
 | 
					  navigate: '[data-test-navigate-button]',
 | 
				
			||||||
  deleteControlGroupToken: sinon.stub(),
 | 
					  navMessage: '[data-test-navigate-message]',
 | 
				
			||||||
  markTokenForUnwrap: sinon.stub(),
 | 
					  tokenInput: '[data-test-token-input]',
 | 
				
			||||||
});
 | 
					  unwrap: '[data-test-unwrap-button]',
 | 
				
			||||||
 | 
					  unwrapForm: '[data-test-unwrap-form]',
 | 
				
			||||||
const storeService = Service.extend({
 | 
					};
 | 
				
			||||||
  adapterFor() {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      toolAction() {
 | 
					 | 
				
			||||||
        return resolve({ data: { foo: 'bar' } });
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
module('Integration | Component | control group success', function (hooks) {
 | 
					module('Integration | Component | control group success', function (hooks) {
 | 
				
			||||||
  setupRenderingTest(hooks);
 | 
					  setupRenderingTest(hooks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  hooks.beforeEach(function () {
 | 
					  hooks.beforeEach(function () {
 | 
				
			||||||
    run(() => {
 | 
					    this.store = this.owner.lookup('service:store');
 | 
				
			||||||
      this.owner.unregister('service:store');
 | 
					    this.transitionStub = sinon.stub(this.owner.lookup('service:router'), 'transitionTo');
 | 
				
			||||||
      this.owner.register('service:control-group', controlGroupService);
 | 
					    this.controlGroup = this.owner.lookup('service:control-group');
 | 
				
			||||||
      this.controlGroup = this.owner.lookup('service:control-group');
 | 
					    this.markTokenForUnwrapStub = sinon.stub(this.controlGroup, 'markTokenForUnwrap');
 | 
				
			||||||
      this.owner.register('service:store', storeService);
 | 
					    this.model = {
 | 
				
			||||||
      this.router = this.owner.lookup('service:router');
 | 
					      approved: false,
 | 
				
			||||||
      this.router.reopen({
 | 
					      requestPath: 'foo/bar',
 | 
				
			||||||
        transitionTo: sinon.stub().returns(resolve()),
 | 
					      id: 'accessor',
 | 
				
			||||||
      });
 | 
					      requestEntity: { id: 'requestor', name: 'entity8509' },
 | 
				
			||||||
      setRunOptions({
 | 
					      reload: sinon.stub(),
 | 
				
			||||||
        rules: {
 | 
					    };
 | 
				
			||||||
          // TODO: swap out JsonEditor with Hds::CodeBlock for display
 | 
					    setRunOptions({
 | 
				
			||||||
          'color-contrast': { enabled: false },
 | 
					      rules: {
 | 
				
			||||||
          label: { enabled: false },
 | 
					        // TODO: swap out JsonEditor with Hds::CodeBlock for display
 | 
				
			||||||
        },
 | 
					        'color-contrast': { enabled: false },
 | 
				
			||||||
      });
 | 
					        label: { enabled: false },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const MODEL = {
 | 
					 | 
				
			||||||
    approved: false,
 | 
					 | 
				
			||||||
    requestPath: 'foo/bar',
 | 
					 | 
				
			||||||
    id: 'accessor',
 | 
					 | 
				
			||||||
    requestEntity: { id: 'requestor', name: 'entity8509' },
 | 
					 | 
				
			||||||
    reload: sinon.stub(),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  test('render with saved token', async function (assert) {
 | 
					  test('render with saved token', async function (assert) {
 | 
				
			||||||
    assert.expect(3);
 | 
					    assert.expect(3);
 | 
				
			||||||
    const response = {
 | 
					    const response = {
 | 
				
			||||||
      uiParams: { url: '/foo' },
 | 
					      uiParams: { url: '/foo' },
 | 
				
			||||||
      token: 'token',
 | 
					      token: 'token',
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    this.set('model', MODEL);
 | 
					 | 
				
			||||||
    this.set('response', response);
 | 
					    this.set('response', response);
 | 
				
			||||||
    await render(hbs`<ControlGroupSuccess @model={{this.model}} @controlGroupResponse={{this.response}} />`);
 | 
					    await render(hbs`<ControlGroupSuccess @model={{this.model}} @controlGroupResponse={{this.response}} />`);
 | 
				
			||||||
 | 
					    assert
 | 
				
			||||||
 | 
					      .dom(SELECTORS.navMessage)
 | 
				
			||||||
 | 
					      .hasText(
 | 
				
			||||||
 | 
					        'You have been granted access to foo/bar. Be careful, you can only access this data once. If you need access again in the future you will need to get authorized again. Visit'
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert.true(component.showsNavigateMessage, 'shows unwrap message');
 | 
					    await click(SELECTORS.navigate);
 | 
				
			||||||
 | 
					    const [transition] = this.transitionStub.lastCall.args;
 | 
				
			||||||
    await component.navigate();
 | 
					    const [accessor] = this.markTokenForUnwrapStub.lastCall.args;
 | 
				
			||||||
    later(() => cancelTimers(), 50);
 | 
					    assert.strictEqual(accessor, 'accessor', 'marks token for unwrap');
 | 
				
			||||||
    await settled();
 | 
					    assert.strictEqual(transition, '/foo', 'calls router transition');
 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert.true(this.controlGroup.markTokenForUnwrap.calledOnce, 'marks token for unwrap');
 | 
					 | 
				
			||||||
    assert.true(this.router.transitionTo.calledOnce, 'calls router transition');
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('render without token', async function (assert) {
 | 
					  test('render without token', async function (assert) {
 | 
				
			||||||
    assert.expect(2);
 | 
					    assert.expect(2);
 | 
				
			||||||
    this.set('model', MODEL);
 | 
					 | 
				
			||||||
    await render(hbs`<ControlGroupSuccess @model={{this.model}} />`);
 | 
					    await render(hbs`<ControlGroupSuccess @model={{this.model}} />`);
 | 
				
			||||||
 | 
					    assert.dom(SELECTORS.unwrapForm).exists();
 | 
				
			||||||
 | 
					    assert.dom(SELECTORS.tokenInput).hasValue('');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert.true(component.showsUnwrapForm, 'shows unwrap form');
 | 
					  test('it unwraps data on submit', async function (assert) {
 | 
				
			||||||
 | 
					    assert.expect(2);
 | 
				
			||||||
    await component.token('token');
 | 
					    const storeService = Service.extend({
 | 
				
			||||||
    component.unwrap();
 | 
					      adapterFor() {
 | 
				
			||||||
    later(() => cancelTimers(), 50);
 | 
					        return {
 | 
				
			||||||
    await settled();
 | 
					          toolAction() {
 | 
				
			||||||
 | 
					            return resolve({ data: { foo: 'bar' } });
 | 
				
			||||||
    assert.true(component.showsJsonViewer, 'shows unwrapped data');
 | 
					          },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.owner.unregister('service:store');
 | 
				
			||||||
 | 
					    this.owner.register('service:store', storeService);
 | 
				
			||||||
 | 
					    await render(hbs`<ControlGroupSuccess @model={{this.model}} />`);
 | 
				
			||||||
 | 
					    assert.dom(SELECTORS.tokenInput).hasValue('');
 | 
				
			||||||
 | 
					    await fillIn(SELECTORS.tokenInput, 'token');
 | 
				
			||||||
 | 
					    await click(SELECTORS.unwrap);
 | 
				
			||||||
 | 
					    const actual = find(SELECTORS.jsonViewer).innerText;
 | 
				
			||||||
 | 
					    const expected = JSON.stringify({ foo: 'bar' }, null, 2);
 | 
				
			||||||
 | 
					    assert.strictEqual(actual, expected, `it renders unwrapped data: ${actual}`);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user