Skip to content

Commit

Permalink
Update for Mirador 4 + Vite
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeer committed Dec 16, 2024
1 parent d578bfb commit 48e8081
Show file tree
Hide file tree
Showing 26 changed files with 45,027 additions and 434 deletions.
4 changes: 0 additions & 4 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
dist/
config/
coverage/
node_modules/
lib/
es/
umd/
83 changes: 77 additions & 6 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,16 +1,87 @@
{
"env": {
"jest/globals": true
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"extends": ["airbnb"],
"extends": [
"airbnb",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:testing-library/react"
],
"globals": {
"page": true,
"document": true
"document": true,
"vi": true
},
"parser": "babel-eslint",
"plugins": ["jest"],
"plugins": [
"react",
"react-hooks",
"testing-library"
],
"rules": {
"import/no-unresolved": [
2, { "ignore": ["test-utils"] }
],
"import/prefer-default-export": "off",
"no-console": "off",
"no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true }],
"no-unused-vars": "off",
"no-undef": "off",
"no-restricted-syntax": ["warn", "WithStatement"],
"no-restricted-globals": ["error"],
"eqeqeq": ["warn", "smart"],
"no-use-before-define": [
"warn",
{
"functions": false,
"classes": false,
"variables": false
},
],
"no-mixed-operators": [
"warn",
{
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"],
],
"allowSamePrecedence": false,
},
],
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-underscore-dangle": "off",
"react/prefer-stateless-function": "off",
"react/jsx-props-no-spreading": "off",
"react/function-component-definition": "off",
"default-param-last": "off",
"arrow-parens": "off",
"import/no-anonymous-default-export": "off",
"import/no-extraneous-dependencies": "off",
"max-len": ["error", {
"code": 120,
"ignoreComments": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true
}],
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
"react/require-default-props": [2, {
"functions": "defaultArguments"
}],
"react-hooks/exhaustive-deps": "error",
"testing-library/render-result-naming-convention": "off",
"testing-library/no-render-in-lifecycle": [
"error",
{
"allowTestingFrameworkSetupHook": "beforeEach"
}
]
}
}
85 changes: 42 additions & 43 deletions __tests__/MiradorShareDialog.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import { shallow } from 'enzyme';
import userEvent from '@testing-library/user-event';
import { render, screen } from './utils/test-utils';
import miradorShareDialog from '../src/MiradorShareDialog';

function createWrapper(props) {
return shallow(
return render(
<miradorShareDialog.component
closeShareDialog={() => {}}
containerId="container-123"
Expand All @@ -13,102 +14,100 @@ function createWrapper(props) {
open
{...props}
/>,
).dive();
);
}

describe('Dialog', () => {
let wrapper;
it('renders a dialog based on the passed in open prop', () => {
wrapper = createWrapper();
expect(wrapper.find('WithStyles(ForwardRef(Dialog))').props().open).toBe(true);
expect(screen.getByRole('dialog')).toBeInTheDocument();
});

it('does not render a dialog when the open prop is false', () => {
wrapper = createWrapper({ open: false });
expect(wrapper.find('WithStyles(ForwardRef(Dialog))').length).toBe(0);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});

it('renders the section headings in an h3', () => {
wrapper = createWrapper();
expect(wrapper.find('WithStyles(ForwardRef(Typography))[variant="h3"]').get(0).props.children).toEqual('Share link');
expect(wrapper.find('WithStyles(ForwardRef(Typography))[variant="h3"]').get(1).props.children).toEqual('Embed');
expect(wrapper.find('WithStyles(ForwardRef(Typography))[variant="h3"]').get(2).props.children).toEqual('Add to another viewer');

expect(screen.getByText('Share link', { selector: 'h3' })).toBeInTheDocument();
expect(screen.getByText('Embed', { selector: 'h3' })).toBeInTheDocument();
expect(screen.getByText('Add to another viewer', { selector: 'h3' })).toBeInTheDocument();
});

it('has a close button that calls closeShareDialog on click', () => {
const closeShareDialog = jest.fn();
const closeShareDialog = vi.fn();
wrapper = createWrapper({ closeShareDialog });
wrapper.find('WithStyles(ForwardRef(DialogActions)) WithStyles(ForwardRef(Button))').simulate('click');
screen.getByRole('button', { name: 'Close' }).click();
expect(closeShareDialog).toHaveBeenCalled();
});

it('has dividers', () => {
wrapper = createWrapper();
expect(wrapper.find('WithStyles(ForwardRef(Divider))').length).toEqual(2);
});

describe('Share link section', () => {
it('renders the section w/ a TextField and a Copy Button', () => {
wrapper = createWrapper();

expect(wrapper.find('WithStyles(ForwardRef(TextField))').length).toBe(1);
expect(wrapper.find('CopyToClipboard WithStyles(ForwardRef(Button))').get(0).props.children).toEqual('Copy');
expect(screen.getByLabelText('Share link URL', { selector: 'input' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Copy link to clipboard' })).toBeInTheDocument();
});

it('renders the TextField & CopyToClipboard components w/ the shareLinkText state value', () => {
it.skip('renders the TextField & CopyToClipboard components w/ the shareLinkText state value', async () => {
const mockedWriteText = vi.spyOn(navigator.clipboard, 'writeText');
wrapper = createWrapper();

wrapper.setState({ shareLinkText: 'http://example.com/iiif/manifest' });
expect(wrapper.find('WithStyles(ForwardRef(TextField))').props().defaultValue).toEqual('http://example.com/iiif/manifest');
expect(wrapper.find('CopyToClipboard').get(0).props.text).toEqual('http://example.com/iiif/manifest');
await userEvent.type(screen.getByLabelText('Share link URL', { selector: 'input' }), '?xyz');

await userEvent.click(screen.getByRole('button', { name: 'Copy link to clipboard' }));
expect(mockedWriteText).toHaveBeenCalledTimes(1);
expect(mockedWriteText).toHaveBeenCalledWith('your copied data');
});

it("sets the component's shareLinkText on TextField change", () => {
it('allows the user to change the embed URL', async () => {
wrapper = createWrapper();
wrapper.find('WithStyles(ForwardRef(TextField))').props().onChange({ target: { value: 'http://example.com/iiif/manifest.json' } });
expect(wrapper.state().shareLinkText).toEqual('http://example.com/iiif/manifest.json');

await userEvent.type(screen.getByLabelText('Share link URL', { selector: 'input' }), '?xyz');

expect(screen.getByLabelText('Share link URL', { selector: 'input' }).value).toEqual('http://example.com/abc/iiif/manifest?xyz');
});

it('does not render the section if the displayShareLink prop is falsey', () => {
wrapper = createWrapper({ displayShareLink: false });

expect(wrapper.find('WithStyles(ForwardRef(TextField))').length).toBe(0);
expect(wrapper.find('CopyToClipboard').length).toBe(1);
expect(screen.queryByLabelText('Share link URL', { selector: 'input' })).not.toBeInTheDocument();
});
});

describe('embed section', () => {
it('is rendered when the displayEmbedOption is true', () => {
wrapper = createWrapper({ displayEmbedOption: false });
expect(wrapper.find('WithStyles(MiradorShareEmbed)').length).toBe(0);
expect(screen.queryByText('Embed', { selector: 'h3' })).not.toBeInTheDocument();
expect(screen.queryByLabelText('Select viewer size')).not.toBeInTheDocument();

wrapper = createWrapper({ displayEmbedOption: true });
expect(wrapper.find('WithStyles(MiradorShareEmbed)').length).toBe(1);
expect(screen.getByText('Embed', { selector: 'h3' })).toBeInTheDocument();
expect(screen.getByLabelText('Select viewer size')).toBeInTheDocument();
});
});

describe('Add to another viewer section', () => {
it('renders a link, icon, button, and text', () => {
it('renders text', () => {
wrapper = createWrapper();

expect(wrapper.find('WithStyles(ForwardRef(Grid)) WithStyles(ForwardRef(Link)) IiifIcon').length).toBe(1);
expect(wrapper.find('WithStyles(ForwardRef(Grid)) CopyToClipboard WithStyles(ForwardRef(Button))').length).toBe(1);
expect(wrapper.find('WithStyles(ForwardRef(Grid)) WithStyles(ForwardRef(Typography))[variant="body1"]').get(0).props.children).toEqual(
'Drag & drop IIIF icon to add this resource to any IIIF viewer.',
);
expect(wrapper.find('WithStyles(ForwardRef(Grid)) WithStyles(ForwardRef(Typography))[variant="body1"]').get(2).props.children).toEqual(
'Copy & paste the resource\'s manifest into any IIIF viewer.',
);
expect(screen.getByText(/Drag & drop/)).toBeInTheDocument();
expect(screen.getByText(/Copy & paste the resource/)).toBeInTheDocument();
});

it('renders the link with IIIF Drag & Drop Compliant URL (passing the manifest in a param)', () => {
const link = wrapper.find('WithStyles(ForwardRef(Grid)) WithStyles(ForwardRef(Link))').at(0);
expect(link.props().href).toEqual('http://example.com/abc/iiif/manifest?manifest=http://example.com/abc/iiif/manifest');
wrapper = createWrapper();

expect(screen.getByLabelText('Drag icon to any IIIF viewer.')).toHaveAttribute('href', 'http://example.com/abc/iiif/manifest?manifest=http://example.com/abc/iiif/manifest');
});

describe('when an info link is configured/passed in as a prop', () => {
it('renders a "What is IIIF" link', () => {
wrapper = createWrapper({ iiifInfoLink: 'http://iiif.io/' });
const link = wrapper.find('WithStyles(ForwardRef(Typography))[variant="body1"] WithStyles(ForwardRef(Link))');
expect(link.props().children).toEqual('What is IIIF?');
expect(link.props().href).toEqual('http://iiif.io/');

expect(screen.getByText('What is IIIF?')).toHaveAttribute('href', 'http://iiif.io/');
});
});
});
Expand Down
1 change: 0 additions & 1 deletion __tests__/MiradorShareEmbed.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import { shallow } from 'enzyme';
import MiradorShareEmbed from '../src/MiradorShareEmbed';

/** Utility function to wrap */
Expand Down
16 changes: 8 additions & 8 deletions __tests__/miradorSharePlugin.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { shallow } from 'enzyme';
import { render, screen } from './utils/test-utils';
import miradorSharePlugin from '../src/miradorSharePlugin';

function createWrapper(props) {
return shallow(
return render(
<miradorSharePlugin.component
handleClose={() => {}}
openShareDialog={() => {}}
Expand All @@ -18,17 +18,17 @@ describe('miradorSharePlugin', () => {
});
describe('renders a component', () => {
it('renders a thing', () => {
const wrapper = createWrapper();
expect(wrapper.find('WithStyles(ForwardRef(ListItemText))').props().children).toEqual('Share');
createWrapper();
expect(screen.getByText('Share')).toBeInTheDocument();
});
});

describe('MenuItem', () => {
it('calls the openShareDialog and handleClose props when clicked', () => {
const handleClose = jest.fn();
const openShareDialog = jest.fn();
const wrapper = createWrapper({ handleClose, openShareDialog });
wrapper.find('WithStyles(ForwardRef(MenuItem))').simulate('click');
const handleClose = vi.fn();
const openShareDialog = vi.fn();
createWrapper({ handleClose, openShareDialog });
screen.getByText('Share').click();
expect(handleClose).toHaveBeenCalled();
expect(openShareDialog).toHaveBeenCalled();
});
Expand Down
54 changes: 54 additions & 0 deletions __tests__/utils/test-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { Provider } from 'react-redux';
import { render } from '@testing-library/react';
import PropTypes from 'prop-types';
import { createStore, applyMiddleware } from 'redux';
import { thunk } from 'redux-thunk';
import { createTheme, ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
import { rootReducer as createRootReducer, settings } from 'mirador';

const rootReducer = createRootReducer();
const theme = createTheme(settings.theme);

/**
* Hook up our rendered object to redux
*/
function renderWithProviders(
ui,
{
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = createStore(rootReducer, preloadedState, applyMiddleware(thunk)),
...renderOptions
} = {},
) {
/** :nodoc: */
function Wrapper({ children }) {
return (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<Provider store={store}>{children}</Provider>
</ThemeProvider>
</StyledEngineProvider>
);
}

Wrapper.propTypes = {
children: PropTypes.node.isRequired,
};

const rendered = render(ui, { wrapper: Wrapper, ...renderOptions });

// Return an object with the store and all of RTL's query functions
return {
store,
...rendered,
rerender: (newUi, options) => render(
newUi,
{ container: rendered.container, wrapper: Wrapper, ...options },
),
};
}

export * from '@testing-library/react';
export { renderWithProviders as render };
13 changes: 0 additions & 13 deletions babel.config.js

This file was deleted.

Loading

0 comments on commit 48e8081

Please sign in to comment.