auth0/auth0-vue

Testing: Casting is required when providing a replacement for the Auth0 client

SimonSimCity opened this issue · 2 comments

Describe the problem

When trying to write a test and provide a mock for Auth0VueClient, I get a type-mismatch when not casting the injection key AUTH0_INJECTION_KEY to symbol.

What was the expected behavior?

My Typescript compiler should not complain

Reproduction

Set up a project which includes this plugin and a component which uses the token for something and start to write tests for it.

For the global.provide-property of the mount options try to register a mock using the key AUTH0_INJECTION_KEY. The Typescript-compiler will start complaining that A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464). The key is of type InjectionKey<Auth0VueClient>, where InjectionKey<T> extends Symbol.

Furthermore, I found this among the do's and dont's in the Typescript documentation:

Don't ever use the types Number, String, Boolean, Symbol, or Object These types refer to non-primitive boxed objects that are
almost never used appropriately in JavaScript code.

/* WRONG */
function reverse(s: String): String;

Do use the types number, string, boolean, and symbol.

/* OK */
function reverse(s: string): string;

https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#general-types

Wouldn't it be better to extend from symbol? Don't know whether that's possible or what you've tried it already ... I just don't like that I have to use casting for the key as in this example:

  it("should add the access token to the given path", async () => {
    // Arrange
    const src = "http://localhost/image.jpg";

    // Act
    const wrapper = mount(ProtectedImage, {
      props: {
        src,
      },
      global: {
        provide: {
          [AUTH0_INJECTION_KEY as symbol]: {
            getAccessTokenSilently: (o) => {
              if (o?.detailedResponse)
                return {
                  id_token: "",
                  access_token: "MySecretAccessToken",
                  expires_in: 0,
                };
              return Promise.resolve("MySecretAccessToken");
            },
          } as Auth0VueClient,
        },
      },
    });
    await flushPromises();

    const el = wrapper.element as HTMLImageElement;

    // Assert
    expect(el.src).eq(`${src}?auth=Bearer+MySecretAccessToken`);
  });

Can the behavior be reproduced using the Vue SDK Playground?

Not tried yet ...

Environment

  • Version of auth0-vue used: 2.0.2
  • Version of vue used: 3.2.47
  • Which browsers have you tested in? -
  • Other modules/plugins/libraries that might be involved: typescript: 4.9.5

Just realized, that the definition of InjectionKey<T> is part of the package @vue/runtime-core which I have installed in version 3.2.47 😅 I also found the issue #5089 there which covers this problem; so let's close this here as out of scope for this project.

One workaround is to use AUTH0_INJECTION_KEY.valueOf() as key, which works as well 😏