// @flow
import type { Node } from 'react';
import axe, { type AxeResults } from 'axe-core';
import { mountWrappedComponent } from './renderer';

let documentWrapper;
export const mountToDocument = (
  jsx: Node,
  mount?: typeof mountWrappedComponent = mountWrappedComponent,
) => {
  if (!documentWrapper) {
    documentWrapper = global.document.createElement('main');
    global.document.body.appendChild(documentWrapper);
  }

  const container = mount(jsx);
  documentWrapper.innerHTML = '';
  documentWrapper.appendChild(container.getDOMNode());

  return container;
};

const axeConfig = {
  rules: {
    // color-contrast doesn't work in JSDOM environments
    'color-contrast': { enabled: false },
  },
};

/**
 * Runs the axe-core audit over a set of HTML
 * @example
 * const { violations } = await auditAccessibility(html);
 * expect(violations).toHaveLength(0);
 * @param {HTMLElement} componentDomNode
 */
export const auditAccessibility = async (
  componentDomNode: HTMLElement,
): Promise<AxeResults> => {
  return axe.run(componentDomNode, axeConfig);
};

type Options = {
  mount?: typeof mountWrappedComponent,
};

/**
 * Tests if a component is WCAG compliant.
 * This will do the assertion for you, just add JSX
 * @example
 * describe('Component', () => {
 *   // will show a test failure as "passes an accessibility audit"
 *   itIsAccessible(<Component />);
 * });
 */
export const itIsAccessible = (jsx: Node, options: ?Options) => {
  it('passes the accessiblity audit', async () => {
    const component = mountToDocument(jsx, options?.mount);
    const { violations } = await auditAccessibility(component.getDOMNode());
    expect(violations).toHaveLength(0);
  });
};
