Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FR: Add fake Auth plugin object for use in unit tests #30

Open
1 of 3 tasks
mfickett opened this issue Nov 5, 2020 · 2 comments
Open
1 of 3 tasks

FR: Add fake Auth plugin object for use in unit tests #30

mfickett opened this issue Nov 5, 2020 · 2 comments

Comments

@mfickett
Copy link

mfickett commented Nov 5, 2020

I'm submitting a:

  • Bug report
  • Feature request
  • Other (Describe below)

Current behavior

Tests either fail because they don't have Auth installed, or try to use the real Auth.

Expected behavior

It would be great to have a fake Vue plugin for Okta auth. Example usage might look like:

import { assert } from "chai";
import { createLocalVue, mount } from "@vue/test-utils";
import MyView from "@views/MyView.vue";
import FakeOktaPlugin from "@okta/okta-vue-testing";

const localVue = createLocalVue();
localVue.use(FakeOktaPlugin);

describe("MyView.vue", () => {
  it("shows an error when not authenticated", () => {
    // need some way to vary behavior by test case
    FakeOktaPlugin.fakeAuth.setAuthenticated(false);

    // now my view can be created and think it's interacting with `$auth`
    const wrapper = mount(MyView, ...etc...);

    // verify that my view did the right thing based on auth state, tokens, etc
    assert.match(wrapper.text(), /not authenticated/);
  });
});

This would allow testing components that use $auth, with configurable behavior from the okta-vue plugin.

The implementation could presumably be similar to the real plugin with an install function, but then have simple setters/getters instead of the full Auth implementation.

@shuowu
Copy link
Contributor

shuowu commented Nov 5, 2020

@mfickett Thanks for submitting the feature request.

Internal Ref: OKTA-343960

@mfickett
Copy link
Author

mfickett commented Nov 6, 2020

In case it's helpful, here's my src/testing/fakeokta.ts. Very basic but works for me for now.

/* eslint-disable */
// Many unused parameters and uses of any.
/**
 * A fake Okta-Vue plugin for use in unit tests.
 *
 * Vue plugin guide: https://vuejs.org/v2/guide/plugins.html
 * modeled after the real Okta-Vue plugin, https://github.com/okta/okta-vue/blob/master/src/Auth.js
 * typings reference:
 *   https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/okta__okta-vue/index.d.ts
 *
 * In tests, install this with
 *   import { fakeOkta } from "@/testing/fakeokta";
 *   Vue.use(fakeOkta);
 * It is installed on Vue (not just localVue) since components use the global Vue.prototype.$auth.
 * Related docs:
 *   https://vue-test-utils.vuejs.org/guides/common-tips.html#applying-global-plugins-and-mixins
 */

import { VueConstructor } from "vue";

class FakeAuth {
  authenticated: boolean;

  constructor() {
    this.authenticated = true;
  }

  setAuthenticated(authenticated: boolean) {
    this.authenticated = authenticated;
  }

  async loginRedirect(fromUri?: string, additionalParams?: any): Promise<void> {
    return;
  }

  async logout(): Promise<void> {
    return;
  }

  async isAuthenticated(): Promise<boolean> {
    return this.authenticated;
  }

  async getIdToken(): Promise<string> {
    return "header.someidtoken.signature";
  }

  async getAccessToken(): Promise<string> {
    return "header.someaccesstoken.signature";
  }

  async getUser(): Promise<any> {
    return { name: "Fake User", preferred_username: "[email protected]" };
  }

  async handleAuthentication(): Promise<void> {
    return;
  }

  getFromUri(): string {
    return "/";
  }
}

function install(Vue: VueConstructor, options: any) {
  Vue.prototype.$auth = new FakeAuth();
}

export default { install };

I ended up having some issues because I call isAuthenticated (which is async) from a lifecycle hook (which is not), so in my tests I had to wait for the async call explicitly even though the lifecycle hook did get called automatically.

import { assert } from "chai";
import { createLocalVue, shallowMount } from "@vue/test-utils";
import Vue from "vue";
import App from "@/App.vue";
import fakeOkta from "@/testing/fakeokta";

const localVue = createLocalVue();
// Even though we're using shallowMount which does not render subcomponents, install VueRouter
Vue.use(fakeOkta);

describe("App.vue", () => {
  it("renders a message that the user is not logged in when $auth.isAuthenticated is false", async () => {
    Vue.prototype.$auth.setAuthenticated(false);

    const wrapper = shallowMount(App, { localVue });
    // Although the created() lifecycle hook is called by shallowMount, pollAuthenticated() is async
    // (and must be b/c Okta's API is async) and created() is synchronous, so we must await the call
    // here to force its processing before the asserts below.
    await wrapper.vm.pollAuthenticated();

    assert.match(wrapper.text(), /Not Authenticated/);
  });
});

I'm not confident that this usage is better than mocking, but I'm anticipating more complex cases where faking may work better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants