Skip to content

Commit

Permalink
Latest
Browse files Browse the repository at this point in the history
  • Loading branch information
rhysyngsun committed Jan 31, 2022
1 parent 98d2d27 commit bb696c4
Show file tree
Hide file tree
Showing 18 changed files with 240 additions and 200 deletions.
109 changes: 54 additions & 55 deletions static/js/components/NotificationContainer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { assert } from "chai"
import { act } from "react-dom/test-utils"
import sinon from "sinon"
import React from "react"
import { ALERT_TYPE_TEXT } from "../constants"
import * as notificationsHooks from "../hooks/notifications"
import { Notifications } from "../hooks/notifications"
import * as notificationsApi from "../lib/notificationsApi"
import { wait } from "../lib/util"
import NotificationContainer from "./NotificationContainer"
import { TextNotification } from "./notifications"
import {render, screen, fireEvent} from "@testing-library/react"
import { wait } from "../lib/util"

describe("NotificationContainer component", () => {
let contextValue: Notifications, getAlertPropsStub
let contextValue: Notifications, getAlertPropsStub: jest.SpyInstance<any>

const renderNotifications = (func = render) => func(<NotificationContainer />)

beforeEach(() => {
contextValue = {
Expand All @@ -20,7 +20,7 @@ describe("NotificationContainer component", () => {
type: ALERT_TYPE_TEXT,
dismissed: false,
props: {
text: "derp"
text: "blep"
}
}
},
Expand All @@ -29,25 +29,21 @@ describe("NotificationContainer component", () => {
jest
.spyOn(notificationsHooks, "useNotifications")
.mockImplementation(() => {
console.log("useNotifications()")
return contextValue
})

getAlertPropsStub = jest
.spyOn(notificationsApi, "getNotificationAlertProps")
.mockReturnValue({})
render = render(NotificationContainer)
})

afterEach(() => {
helper.cleanup()
})

it("shows notifications", async () => {
const { wrapper } = await render()
const alerts = wrapper.find("Alert")
assert.lengthOf(alerts, Object.keys(contextValue.notifications).length)
assert.equal(alerts.at(0).prop("children").type, TextNotification)
renderNotifications()

const alerts = await screen.findAllByRole("alert")

expect(alerts).toHaveLength(Object.keys(contextValue.notifications).length)
expect(alerts[0].children[1].innerHTML).toEqual("blep")
})

it("uses TextNotification as the default inner component", async () => {
Expand All @@ -56,15 +52,18 @@ describe("NotificationContainer component", () => {
type: "unrecognized-type",
dismissed: false,
props: {
text: "derp"
text: "blep"
}
}
}
const { wrapper } = await render()
const alerts = wrapper.find("Alert")
assert.lengthOf(alerts, Object.keys(contextValue.notifications).length)
assert.equal(alerts.at(0).prop("children").type, TextNotification)
renderNotifications()

const alerts = await screen.findAllByRole("alert")

expect(alerts).toHaveLength(Object.keys(contextValue.notifications).length)
expect(alerts[0].children[1].innerHTML).toEqual("blep")
})

;[
[undefined, "info"],
["danger", "danger"]
Expand All @@ -82,14 +81,18 @@ describe("NotificationContainer component", () => {
}
}
}
const { wrapper } = await render()
assert.equal(wrapper.find("Alert").prop("color"), expectedColor)
sinon.assert.calledWith(getAlertPropsStub, ALERT_TYPE_TEXT)

renderNotifications()

const alert = await screen.findByRole("alert")

expect(alert).toHaveClass(`alert-${expectedColor}`)
expect(getAlertPropsStub).toBeCalledWith(ALERT_TYPE_TEXT)
})
})

it("uses a default color value for the alert type if a color was not exactly specified", async () => {
getAlertPropsStub.returns({
getAlertPropsStub.mockReturnValue({
color: "some-color"
})
contextValue.notifications = {
Expand All @@ -100,44 +103,40 @@ describe("NotificationContainer component", () => {
}
}
}
const { wrapper } = await render()
assert.equal(wrapper.find("Alert").prop("color"), "some-color")
sinon.assert.calledWith(getAlertPropsStub, "some-type")
renderNotifications()

const alert = await screen.findByRole("alert")

expect(alert).toHaveClass("alert-some-color")
expect(getAlertPropsStub).toBeCalledWith("some-type")
})

it("hides a message when it's dismissed, then removes it from global state", async () => {
const { wrapper } = await render()
let alert = wrapper.find("Alert").at(0)
const toggleAlert: () => void = alert.prop("toggle")

expect(alert.prop("isOpen")).toBeTruthy()

await act(async () => {
console.log("before toggle")
await toggleAlert!()
console.log("after toggle")

// simulate useNotifications() internals
contextValue = {
...contextValue,
notifications: {
message1: {
...contextValue.notifications.message1,
dismissed: true
}
const {rerender} = renderNotifications()

const closeBtn = await screen.findByRole("button")

await fireEvent.click(closeBtn)

// simulate useNotifications() internals
contextValue = {
...contextValue,
notifications: {
message1: {
...contextValue.notifications.message1,
dismissed: true
}
}
}

wrapper.update()
console.log("after update")
rerender(<NotificationContainer/>)

await wait(10)
})
expect(contextValue.dismissNotification).toBeCalledWith("message1", expect.anything())

expect(contextValue.dismissNotification).toBeCalledWith("message1")
await wait(1500)

alert = wrapper.find("Alert").at(0)
const alert = await screen.queryAllByRole("alert")

expect(alert.prop("isOpen")).toBeFalsy()
expect(alert).toEqual([])
})
})
2 changes: 2 additions & 0 deletions static/js/components/PrivateRoute.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ describe("PrivateRoute component", () => {
helper = new IntegrationTestHelper()
renderComponent = helper.configureRenderer(RoutedDummyComponent)
})

afterEach(() => {
helper.cleanup()
})

;[
[false, loggedInUser, "load the route"],
[true, anonUser, "redirect to the login page with a 'next' param"]
Expand Down
4 changes: 3 additions & 1 deletion static/js/components/PrivateRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { ComponentType } from "react"
import { useLocation} from "react-router"
import { Redirect, Route } from "react-router-dom"
import useCurrentUser from "../hooks/user"
import { generateLoginRedirectUrl } from "../lib/auth"
Expand All @@ -12,6 +13,7 @@ export default function PrivateRoute({
component: Component,
...routeProps
}: Props) {
const location = useLocation()
const user = useCurrentUser()
return (
<Route
Expand All @@ -20,7 +22,7 @@ export default function PrivateRoute({
return user && user.is_authenticated ? (
<Component {...props} />
) : (
<Redirect to={generateLoginRedirectUrl()} />
<Redirect to={generateLoginRedirectUrl(location)} />
)
}}
/>
Expand Down
1 change: 1 addition & 0 deletions static/js/components/forms/ChangeEmailForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Props = {
onSubmit: (...args: Array<any>) => any
user: User
}

export type ChangeEmailFormValues = {
email: string
confirmPassword: string
Expand Down
2 changes: 1 addition & 1 deletion static/js/components/forms/LoginPasswordForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { findFormikFieldByName } from "../../lib/test_utils"
import LoginPasswordForm from "./LoginPasswordForm"

describe("LoginPasswordForm", () => {
let sandbox, onSubmitStub
let sandbox, onSubmitStub: sinon.SinonStub

const renderForm = () =>
shallow(<LoginPasswordForm onSubmit={onSubmitStub} />)
Expand Down
24 changes: 14 additions & 10 deletions static/js/containers/App.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert } from "chai"
import sinon from "sinon"
import * as notificationsHooks from "../hooks/notifications"
import * as notificationsApi from "../lib/notificationsApi"
import { routes } from "../lib/urls"
import IntegrationTestHelper, {
Expand All @@ -12,7 +12,8 @@ describe("Top-level App", () => {
renderPage: TestRenderer,
getStoredUserMessageStub: sinon.SinonStub,
removeStoredUserMessageStub: sinon.SinonStub,
getCurrentUserStub: sinon.SinonStub
getCurrentUserStub: sinon.SinonStub,
addNotificationStub: sinon.SinonStub

beforeEach(() => {
helper = new IntegrationTestHelper()
Expand All @@ -23,6 +24,12 @@ describe("Top-level App", () => {
notificationsApi,
"removeStoredUserMessage"
)
addNotificationStub = helper.sandbox.stub()
helper.sandbox.stub(notificationsHooks, "useNotifications").returns({
addNotification: addNotificationStub,
notifications: {},
dismissNotification: helper.sandbox.stub()
})
getCurrentUserStub = helper.mockGetRequest("/api/users/me", {})
helper.browserHistory.push(routes.root)
renderPage = helper.configureRenderer(App)
Expand All @@ -43,14 +50,11 @@ describe("Top-level App", () => {
text: "some text"
}
getStoredUserMessageStub.returns(userMsg)
const { store } = await renderPage()
const { ui } = store.getState()
assert.deepEqual(ui.userNotifications, {
"loaded-user-msg": {
type: userMsg.type,
props: {
text: userMsg.text
}
await renderPage()
sinon.assert.calledOnceWithExactly(addNotificationStub, "loaded-user-msg", {
type: userMsg.type,
props: {
text: userMsg.text
}
})
sinon.assert.calledOnce(removeStoredUserMessageStub)
Expand Down
23 changes: 14 additions & 9 deletions static/js/containers/HeaderApp.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assert } from "chai"
import sinon from "sinon"
import * as notificationsHooks from "../hooks/notifications"
import * as notificationsApi from "../lib/notificationsApi"
import IntegrationTestHelper, {
TestRenderer
Expand All @@ -10,7 +11,8 @@ describe("Top-level HeaderApp", () => {
let helper: IntegrationTestHelper,
renderPage: TestRenderer,
getStoredUserMessageStub: sinon.SinonStub,
removeStoredUserMessageStub: sinon.SinonStub
removeStoredUserMessageStub: sinon.SinonStub,
addNotificationStub: sinon.SinonStub

beforeEach(() => {
helper = new IntegrationTestHelper()
Expand All @@ -21,6 +23,12 @@ describe("Top-level HeaderApp", () => {
notificationsApi,
"removeStoredUserMessage"
)
addNotificationStub = helper.sandbox.stub()
helper.sandbox.stub(notificationsHooks, "useNotifications").returns({
addNotification: addNotificationStub,
notifications: {},
dismissNotification: helper.sandbox.stub()
})
renderPage = helper.configureRenderer(HeaderApp)
})

Expand All @@ -40,14 +48,11 @@ describe("Top-level HeaderApp", () => {
text: "some text"
}
getStoredUserMessageStub.returns(userMsg)
const { store } = await renderPage()
const { ui } = store.getState()
assert.deepEqual(ui.userNotifications, {
"loaded-user-msg": {
type: userMsg.type,
props: {
text: userMsg.text
}
await renderPage()
sinon.assert.calledOnceWithExactly(addNotificationStub, "loaded-user-msg", {
type: userMsg.type,
props: {
text: userMsg.text
}
})
sinon.assert.calledOnce(removeStoredUserMessageStub)
Expand Down
Loading

0 comments on commit bb696c4

Please sign in to comment.