Skip to content

Instantly share code, notes, and snippets.

@EmmaB
Last active November 25, 2021 17:31
Show Gist options
  • Save EmmaB/6b998fc9bb2e710f73cd1f72a9fbef8b to your computer and use it in GitHub Desktop.
Save EmmaB/6b998fc9bb2e710f73cd1f72a9fbef8b to your computer and use it in GitHub Desktop.
WIP contribs
import React, { useContext } from "react"
import * as yup from "yup"
import WorkContext from "contexts/work_context"
import Link from "components/external_link"
import Form from "components/editable_area/components/form"
import NumberField from "components/editable_area/components/number_field"
import ProductIdsCheckboxField from "./form/product_ids_checkbox_field"
import OnixCodeField from "./form/onix_code_field"
import { ContactSelectField } from "components/editable_area/components/contact_select_field"
const OnixCode = ({ code, description }) => (
<>
<span
className="pill pill--label pill--green"
dangerouslySetInnerHTML={{ __html: code }}
/>
<span dangerouslySetInnerHTML={{ __html: description }} />
</>
)
const onixCode = () =>
yup.string().transform(function (value, originalValue) {
if (this.isType(value)) return value
return originalValue?.value
})
const ContributionFormSchema = yup
.object()
.shape({
productIds: yup.array().nullable().default([]).of(yup.number().nullable()),
sequenceNumber: yup
.number()
.min(1)
.default(1)
.nullable()
.required("You need a position")
.label("Position"),
contributor: yup
.mixed()
.required("You need a contributor")
.label("Contributor")
.transform(values => {
if (values) {
return values.value
} else {
return undefined
}
}),
onixContributorRole: yup.object().nullable(),
onixContributorRoleCode: onixCode().nullable(),
})
.from("onixContributorRole", "onixContributorRoleCode")
.noUnknown()
export const ShowComponent = ({
contributor,
productIds,
onixContributorRole,
}) => {
const work = useContext(WorkContext)
return (
<ul>
<li>
{onixContributorRole ? <OnixCode {...onixContributorRole} /> : null}{" "}
</li>
<li>
<Link href={`/contacts/${contributor?.id}`}>
{contributor?.personName} {contributor?.organisationName}
</Link>
</li>
<li>
Products:
{/* Need to copy the array first, as sorting tries to mutate the original */}
{[...productIds].sort().map((product, index) => (
<span key={index}>
{" "}
{work.products.find(x => x.id === product).isbn?.isbn13}
</span>
))}
</li>
</ul>
)
}
export const FormComponent = props => {
const work = useContext(WorkContext)
// Says whether the checkbox is checked or not, depending on whether the product id is already
// in the productIds array
const checked = product =>
props.attributes
? props.attributes.productIds.includes(product)
? true
: false
: false
return (
<Form schema={ContributionFormSchema} {...props}>
{work &&
work.products.map((product, index) => (
<ProductIdsCheckboxField
key={index}
label={`${product.isbn?.isbn13}`}
name={product.id}
value={product.id}
defaultChecked={checked(product.id)}
hint={`Check the box if this contact contributed to ${product.isbn?.isbn13}`}
/>
))}
<NumberField name="sequenceNumber" label="Position" />
{work && (
<ContactSelectField
name="contributor"
label="Contributor"
clientId={work.clientId}
className="form__input--half"
/>
)}
<OnixCodeField
name="onixContributorRole"
label="Contributor role"
hint="The role done by this contributor on this work"
listNumber={17}
isClearable={true}
/>
</Form>
)
}
# test
import { screen, waitFor, within, prettyDOM } from "@testing-library/react"
import { graphql } from "msw"
import userEvent from "@testing-library/user-event"
import {
workFactory,
contributionFactory,
contactFactory,
onixCodeFactory,
} from "../../factories"
import { server } from "../../msw/server"
import renderComponent from "./render_component"
import { selectFrom, clearSelect } from "../../support/utils"
const ONIX_CODE_DESCRIPTIONS = {
A01: "By (author)",
B01: "Edited by",
E02: "Dancer",
}
const buildOnixCode = (code, description) =>
onixCodeFactory.build({
code,
description,
value: !isNaN(code) ? `_${code}` : code,
})
const buildOnixCodeFromValue = value =>
value
? buildOnixCode(value.replace("_", ""), ONIX_CODE_DESCRIPTIONS[value])
: null
it("has the Contributors region", () => {
renderComponent()
expect(
screen.getByRole("region", { name: "Contributors" })
).toBeInTheDocument()
})
it("shows a loading message in the Contributors region", () => {
renderComponent()
const region = screen.getByRole("region", { name: "Contributors" })
expect(region).toHaveTextContent("Loading...")
})
describe("shows the contributor information", () => {
let work
beforeEach(() => {
work = workFactory.build({
contributions: [
contributionFactory.build({
contributor: contactFactory.build(),
onixContributorRole: buildOnixCode("A01", "By (author)"),
}),
],
})
server.use(
graphql.query("GetWork", (_req, res, ctx) => {
return res(
ctx.data({
work,
})
)
})
)
})
it("shows the contributor's role in the Contributors region", async () => {
renderComponent()
const region = screen.getByRole("region", { name: "Contributors" })
await waitFor(() => {
expect(region).toHaveTextContent("A01: By (author)")
})
})
})
describe("updates the contributor", () => {
let work
beforeEach(() => {
work = workFactory.build({
contributions: [
contributionFactory.build({
contributor: contactFactory.build({
label: "Alain Marley",
personName: "Alain Marley",
}),
onixContributorRole: buildOnixCode("A01", "By (author)"),
}),
],
})
server.use(
graphql.query("GetWork", (_req, res, ctx) => {
return res(
ctx.data({
work,
})
)
}),
graphql.mutation("UpdateContribution", (req, res, ctx) => {
const { ...contributionAttributes } = req.variables.input
const updatedContribution = {
...contributionAttributes,
}
return res(
ctx.data({
updateContribution: {
contribution: updatedContribution,
errors: [],
},
})
)
})
)
})
it("updates the contribution with a new role", async () => {
renderComponent()
const region = screen.getByRole("region", { name: "Contributors" })
await waitFor(() => {
userEvent.click(within(region).getByRole("button", { name: "Edit" }))
})
await selectFrom(region, "Contributor role", "Edited by")
userEvent.click(screen.getByRole("button", { name: "Save" }))
await waitFor(() => {
expect(region).toHaveTextContent("B01: Edited by")
// Ensure the form has been closed
expect(
screen.queryByRole("button", { name: "Save" })
).not.toBeInTheDocument()
})
})
})
# Cucumber
@javascript
Feature: Work metadata contributions
Background:
Given I'm logged in as a user of "Fauxbooks"
And the client "Fauxbooks" has the following work:
| title |
| Tales of Monkey Island |
And the work "Tales of Monkey Island" has the following products:
| isbn |
| 9781905005123 |
| 9781905005888 |
And the following onix code lists:
| list_number | list_description |
| 17 | Contributor role code |
And the onix code list with a description of "Contributor role code" has the following onix codes:
| value | description | notes |
| A01 | By (author) | a |
| B01 | Edited by | aa |
| A04 | Libretto by | aa |
| B06 | Translated by | aa |
| E03 | Narrator | aa |
Scenario: Add a contribution
Given the client "Fauxbooks" has the following contact:
| names_before_key | keynames |
| Captain | Marley |
And I am on the editable metadata page for "Tales of Monkey Island"
When I begin to add the following contribution:
| Position | 1 |
| Contributor role | Libretto by |
| Contributor | Captain Marley |
And I mark the following as included products:
| isbn |
| 9781905005123 |
| 9781905005888 |
Then I should see the following contribution:
"""
Products: 9781905005123 9781905005888
A04: Libretto by
Name: Captain Marley
"""
And the work "Tales of Monkey Island" should have the following contributions:
| contact | work_contact_role | products_count |
| Captain Marley | A04 | 2 |
# Scenario: Add a contribution with conflicting data
# Given the client "Fauxbooks" has the following contact:
# | names_before_key | keynames |
# | Captain | Marley |
# And the work "Tales of Monkey Island" has the following contributions:
# | contact | work_contact_role | sequence_number |
# | Captain Marley | B01 | 1 |
# And I am on the editable metadata page for "Tales of Monkey Island"
# When I add the following contribution:
# | Position | 1 |
# | Role | Libretto by |
# | Contributor | Captain Marley |
# Then I should see a validation error on "Position" that says "Sequence number has already been taken"
Scenario: Attempt to add a contribution with invalid fields
Given the client "Fauxbooks" has the following contact:
| names_before_key | keynames |
| Captain | Marley |
And the work "Tales of Monkey Island" has the following contributions:
| contact | work_contact_role | sequence_number |
| Captain Marley | B01 | 1 |
And I am on the editable metadata page for "Tales of Monkey Island"
When I add the following contribution:
| Position | 0 |
Then I should see a validation error on "Position" that says "Position must be greater than or equal to 1"
And I should see a validation error on "Contributor" that says "You need a contributor"
Scenario: Edit a contribution
Given the client "Fauxbooks" has the following contact:
| names_before_key | keynames |
| Elaine | Marley |
| Capt | Marley |
And the work "Tales of Monkey Island" has the following contributions:
| contact | work_contact_role |
| Elaine Marley | B01 |
| Capt Marley | B06 |
And I am on the editable metadata page for "Tales of Monkey Island"
When I edit the "Edited by" contribution to:
| Contributor role | Narrator |
Then I should see the following contribution:
"""
E03: Narrator
Name: Elaine Marley
"""
Scenario: Remove a contribution
Given the client "Fauxbooks" has the following contact:
| names_before_key | keynames |
| Elaine | Marley |
| Herman | Toothrot |
And the work "Tales of Monkey Island" has the following contributions:
| contact | work_contact_role |
| Elaine Marley | B01 |
| Herman Toothrot | B06 |
And I am on the editable metadata page for "Tales of Monkey Island"
When I delete the "Edited by" contribution of "Elaine Marley"
Then I should not see the following contribution:
"""
Name: Elaine Marley
Contributor role: Edited by
"""
And the work "Tales of Monkey Island" should have the following contributions:
| contact | work_contact_role |
| Herman Toothrot | B06 |
Scenario: Reorder a contribution
Given the client "Fauxbooks" has the following contact:
| names_before_key | keynames |
| Elaine | Marley |
| Capt | Marley |
| Capt | Snarley |
| Sgt | Barley |
And the work "Tales of Monkey Island" has the following contributions:
| contact | work_contact_role |
| Elaine Marley | B01 |
| Capt Snarley | B03 |
| Capt Marley | B06 |
| Sgt Barley | B02 |
And I am on the editable metadata page for "Tales of Monkey Island"
When I drag the "B01" contribution to after "B06"
Then the work "Tales of Monkey Island" should have the following sorted contributions:
| contact |
| Capt Snarley |
| Capt Marley |
| Elaine Marley |
| Sgt Barley |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment