UNPKG

stitch-ui

Version:

373 lines (333 loc) 11.5 kB
/* global it, describe, beforeAll, afterEach, expect, test */ import React from "react"; // eslint-disable-line no-unused-vars import { Provider } from "react-redux"; import { JSDOM } from "jsdom"; import { MemoryRouter } from "react-router-dom"; import { mount, ReactWrapper } from "enzyme"; import { testSetup, noConsoleErrorsAllowed, stubConfirmation } from "../../testutil"; import * as homeActions from "../../home/actions"; import * as actions from "../actions"; import Authentication from "../components/Authentication"; import AllowedRequestOrigins from "../components/AllowedRequestOrigins"; global.navigator = { userAgent: "node.js" }; const doc = new JSDOM("<!doctype html><html><body></body></html>"); global.document = doc; global.window = doc.defaultView; describe("auth", () => { noConsoleErrorsAllowed(); let store; let testApp; let display; let actionSub; beforeAll(async () => { const testHarness = await testSetup(); store = testHarness.store; actionSub = testHarness.actionSub; testApp = await store.dispatch( homeActions.createApp(testHarness.groupId, "my-test-app") ); return new Promise(resolve => { actionSub.subscribe(actions.loadProvidersActions.rcv.getType(), resolve); display = mount( <Provider store={store}> <MemoryRouter> <div> <Authentication app={testApp} match={{ url: "/" }} /> </div> </MemoryRouter> </Provider> ); }); }); afterEach(() => { actionSub.reset(); }); it("loads the providers", async () => { expect(display.find("AuthProvider").length).toBe(6); }); it("can enable and disable anonymous login", async () => { // Open the modal display .find("AuthProvider") .findWhere(x => x.props().title === "Allow users to log in anonymously") .find("button") .findWhere(x => x.text() === "Edit") .props() .onClick(); const anonLoginModal = display .find("AuthProvider") .findWhere(x => x.props().title === "Allow users to log in anonymously") .at(0).node.modal.portal; const anonModalContent = new ReactWrapper(anonLoginModal, anonLoginModal); expect(store.getState().auth.auth.providers).toEqual({}); await anonModalContent .find("input[type='checkbox']") .props() .onChange({ target: { checked: false } }); expect(store.getState().auth.auth.providers).toEqual({}); }); it("get an error when saving an oauth provider with invalid data", async () => { const goog = display .find("AuthProvider") .findWhere(x => x.props().title === "Google"); goog.find("button").findWhere(x => x.text() === "Edit").props().onClick(); const googModal = new ReactWrapper( goog.node.modal.portal, goog.node.modal.portal ); googModal .find("input[id='enable-Google']") .props() .onChange({ target: { checked: true } }); await googModal .find("input[name='clientId']") .props() .onChange({ target: { value: "testclientid" } }); await googModal .find("button") .findWhere(b => b.text() === "Save") .props() .onClick(); expect(googModal.find(".banner-error")).toHaveLength(1); expect(googModal.find(".banner-error").text()).toContain( "clientSecret is a required string for OAuth2 configuration" ); }); it("can save an oauth provider successfully", async () => { const goog = display .find("AuthProvider") .findWhere(x => x.props().title === "Google"); goog.find("button").findWhere(x => x.text() === "Edit").props().onClick(); const googModal = new ReactWrapper( goog.node.modal.portal, goog.node.modal.portal ); googModal .find("input[id='enable-Google']") .props() .onChange({ target: { checked: true } }); googModal .find("input[name='clientId']") .props() .onChange({ target: { value: "testclientid" } }); googModal .find("input[name='clientSecret']") .props() .onChange({ target: { value: "testclientsecret" } }); googModal.find("button[name='addRedirectURI']").simulate("click"); googModal.find("button[name='addDomainRestriction']").simulate("click"); googModal .find("input[name='redirectURI/0']") .props() .onChange({ target: { value: "http://localhost:8000" } }); googModal .find("input[name='domainRestriction/0']") .props() .onChange({ target: { value: "domain.com" } }); // ensure empty redirect URIs and domain restrictions are ignored googModal.find("button[name='addRedirectURI']").simulate("click"); googModal.find("button[name='addDomainRestriction']").simulate("click"); googModal .find("input[name='metadataFields/email']") .props() .onChange({ target: { checked: true } }); await googModal .find("button") .findWhere(b => b.text() === "Save") .props() .onClick(); expect(googModal.find(".banner-error")).toHaveLength(0); expect(store.getState().auth.auth.providers).toEqual({ "oauth2/google": { clientId: "testclientid", clientSecret: "testclientsecret", redirectURIs: ["http://localhost:8000"], domainRestrictions: ["domain.com"], metadataFields: ["email"] } }); }); it("can create/enable/disable/delete an API key", async () => { const apiKeys = display .find("AuthProvider") .findWhere(x => x.props().title === "API Keys"); apiKeys .find("button") .findWhere(x => x.text() === "Edit") .props() .onClick(); const apiKeyModal = new ReactWrapper( apiKeys.node.modal.portal, apiKeys.node.modal.portal ); expect(apiKeyModal.find("input[type='checkbox']")).toHaveLength(1); expect(store.getState().auth.auth.providers).not.toHaveProperty("api/key"); // enable api/key provider await apiKeyModal .find("input[type='checkbox']") .props() .onChange({ target: { checked: true } }); expect(store.getState().auth.auth.providers).toHaveProperty("api/key"); // disable api/key provider await apiKeyModal .find("input[type='checkbox']") .props() .onChange({ target: { checked: false } }); expect(store.getState().auth.auth.providers).not.toHaveProperty("api/key"); apiKeyModal.find("button[name='createAPIKey']").simulate("click"); apiKeyModal .find("input[name='newKeyName']") .props() .onChange({ target: { value: "newname" } }); // Create new key await apiKeyModal .find("button") .findWhere(x => x.text() === "Save") .props() .onClick(); const apiKeysStored = store.getState().auth.apiKeys.apiKeys.toJS(); const apiKeyKey = Object.keys(apiKeysStored)[0]; expect(Object.keys(apiKeysStored)).toHaveLength(1); expect(apiKeysStored[apiKeyKey].name).toEqual("newname"); expect(apiKeyModal.find("input[type='checkbox']")).toHaveLength(2); // Disable it await apiKeyModal .find("input[type='checkbox']") .at(1) .props() .onChange({ target: { checked: false } }); expect(store.getState().auth.apiKeys.apiKeys.get(apiKeyKey).disabled).toBe( true ); // Delete it stubConfirmation(true); await apiKeyModal.find("button[name='deleteAPIKey']").props().onClick(); expect(store.getState().auth.apiKeys.apiKeys.toJS()).toEqual({}); // Attempt to add new key with invalid name apiKeyModal.find("button[name='createAPIKey']").simulate("click"); apiKeyModal .find("input[name='newKeyName']") .props() .onChange({ target: { value: "invalid newname" } }); await apiKeyModal .find("button") .findWhere(x => x.text() === "Save") .props() .onClick(); expect(store.getState().auth.apiKeys.apiKeys.toJS()).toEqual({}); expect(apiKeyModal.find(".banner-error")).toHaveLength(1); expect(apiKeyModal.find(".banner-error").text()).toMatch( "can only contain ASCII letters, numbers, underscores, and hyphens" ); // Attempt to add new key with empty name apiKeyModal.find("button[name='createAPIKey']").simulate("click"); apiKeyModal .find("input[name='newKeyName']") .props() .onChange({ target: { value: "" } }); await apiKeyModal .find("button") .findWhere(x => x.text() === "Save") .props() .onClick(); expect(store.getState().auth.apiKeys.apiKeys.toJS()).toEqual({}); expect(apiKeyModal.find(".banner-error")).toHaveLength(1); expect(apiKeyModal.find(".banner-error").text()).toMatch( "'name' is a required string" ); }); }); describe("allowed request origins", () => { noConsoleErrorsAllowed(); let store; let testApp; let display; let actionSub; beforeAll(async () => { const testHarness = await testSetup(); store = testHarness.store; actionSub = testHarness.actionSub; testApp = await store.dispatch( homeActions.createApp(testHarness.groupId, "my-test-app") ); display = mount( <Provider store={store}> <MemoryRouter> <div> <AllowedRequestOrigins app={testApp} match={{ url: "/" }} /> </div> </MemoryRouter> </Provider> ); }); afterEach(() => { actionSub.reset(); }); let modalContent; it("can show the modal", async () => { // Open the modal display .find("AllowedRequestOrigins") .find("button") .findWhere(x => x.text() === "Edit") .props() .onClick(); const originsModal = display .find("AllowedRequestOrigins") .find("Modal") .at(0).node.portal; modalContent = new ReactWrapper(originsModal, originsModal); expect( modalContent.find("button[name='addAllowedRequestOrigin']").length ).toBe(1); }); test("saving invalid origins fails", async () => { const addButton = modalContent.find( "button[name='addAllowedRequestOrigin']" ); await addButton.props().onClick(); await addButton.props().onClick(); await addButton.props().onClick(); const saveButton = modalContent.find( "button[name='saveAllowedRequestOrigins']" ); await saveButton.props().onClick(); expect(modalContent.find(".banner-error").text()).toContain( "invalid origin" ); }); test("correcting only some of the origins and saving again should still fail", async () => { await modalContent .find("input[name='origin/0']") .props() .onChange({ target: { value: "https://origin1.com" } }); const saveButton = modalContent.find( "button[name='saveAllowedRequestOrigins']" ); await saveButton.props().onClick(); expect(modalContent.find(".banner-error").text()).toContain( "invalid origin" ); }); test("correcting all the origins and saving again works", async () => { await modalContent .find("input[name='origin/1']") .props() .onChange({ target: { value: "https://origin2.com" } }); await modalContent .find("input[name='origin/2']") .props() .onChange({ target: { value: "https://origin3.com" } }); const saveButton = modalContent.find( "button[name='saveAllowedRequestOrigins']" ); await saveButton.props().onClick(); expect(modalContent.find("Error").at(1).find("div").length).toEqual(0); }); });