运行npm test时发生意外的令牌错误-配置错误?

时间:2020-05-11 19:08:15

标签: reactjs jestjs react-testing-library

●测试套件无法运行

Jest encountered an unexpected token

This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

Here's what you can do:
 • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
 • If you need a custom transformation specify a "transform" option in your config.
 • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html

Details:

SyntaxError: C:\Projects\myProject\src\__tests__\Event.test.js: Unexpected token (354:4)

  352 | 
  353 |   it('renders without errors', (done) => {
> 354 |     const { getByTestId } =  render(
      |     ^
  355 |       <Router history={history}>
  356 |           <Home />
  357 |                     </Router>

  at Object._raise (node_modules/@babel/parser/src/parser/location.js:241:45)
  at Object.raiseWithData (node_modules/@babel/parser/src/parser/location.js:236:17)
  at Object.raise (node_modules/@babel/parser/src/parser/location.js:220:17)
  at Object.unexpected (node_modules/@babel/parser/src/parser/util.js:149:16)
  at Object.parseExprAtom (node_modules/@babel/parser/src/parser/expression.js:1144:20)
  at Object.parseExprAtom (node_modules/@babel/parser/src/plugins/jsx/index.js:532:22)
  at Object.parseExprSubscripts (node_modules/@babel/parser/src/parser/expression.js:539:23)
  at Object.parseMaybeUnary (node_modules/@babel/parser/src/parser/expression.js:519:21)
  at Object.parseExprOps (node_modules/@babel/parser/src/parser/expression.js:311:23)
  at Object.parseMaybeConditional (node_modules/@babel/parser/src/parser/expression.js:263:23)

这是我的配置文件: package.json

{
  "name": "ant4",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "antd": "^4.2.0",
    "aws-amplify": "^2.3.0",
    "axios": "^0.19.2",
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.3.4",
    "@babel/register": "^7.0.0",
    "lodash": "^4.17.15",
    "moment": "^2.25.3",
    "moment-timezone": "^0.5.27",
    "node-jsencrypt": "^1.0.0",
    "react": "^16.13.1",
    "react-copy-to-clipboard": "^5.0.2",
    "react-dnd": "^10.0.2",
    "react-dom": "^16.13.1",
    "react-router": "^5.1.2",
    "react-router-dom": "^5.1.2",
    "react-scripts": "^3.4.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "@testing-library/dom": "^7.5.1",
    "axios-mock-adapter": "^1.18.1",
    "babel-preset-jest": "^24.3.0",
    "babel-preset-env": "^1.7.0",
    "jest": "^24.5.0"
  },
  "babel": {
    "babelrc": false,
    "presets": [
      "es2015"
    ],
    "plugins": [
      "transform-class-properties"
    ]
  }
}

jest.config.js

module.exports = {
    modulePaths: ["/shared/vendor/modules"],
  collectCoverageFrom: ["src/**/*.{js,jsx,mjs}"],
  testMatch: ["<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}", "<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"],
  transform: {
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.js"
  },
  transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$"],
  moduleDirectories: ["node_modules", "bower_components", "shared"],
  moduleFileExtensions: ["js", "jsx", "json"],
  verbose: true,
  moduleNameMapper
};

webpack.config.js

module.exports = {
  module: {
    loaders: [
      {exclude: ['node_modules'], loader: 'babel', test: /\.jsx?$/},
      {loader: 'style-loader!css-loader', test: /\.css$/},
      {loader: 'url-loader', test: /\.gif$/},
      {loader: 'file-loader', test: /\.(ttf|eot|svg)$/},
    ],
  },
  resolve: {
    alias: {
      config$: './configs/app-config.js',
      react: './vendor/react-master',
    },
    extensions: ['', 'js', 'jsx'],
    modules: [
      'node_modules',
      'bower_components',
      'shared',
      '/shared/vendor/modules',
    ],
  },
};

我曾经有一个babel.config.js,但是它什么也没做,所以我删除了它。

fileTransformer.js

const path = require('path');

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
  },
};

我想念什么?需要更改什么?我尝试了尽可能地遵循这些开玩笑的文档:https://jestjs.io/docs/en/webpack

任何帮助,非常感谢。

Events.test.js

Object.defineProperty(window, "matchMedia", {
  writable: true,
  value: jest.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(), // deprecated
    removeListener: jest.fn(), // deprecated
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

import ReactDOM from "react-dom";
import axios from 'axios';
import Events from "../Components/Events/index";
import Home from "../Components/Home";
import { Router, BrowserRouter, MemoryRouter } from "react-router-dom";
import moment from 'moment-timezone';
import { createMemoryHistory } from "history";
import { Auth } from "aws-amplify";

describe('Event', () => {
  jest.mock("../apis");
  const path = "/events";
  const route = "/events";
  const history = createMemoryHistory({ initialEntries: [route] });

  let props = {
    match: {
      path: path,
      url: route,
      isExact: true,
      params: {
        ...
      }
    },
    location: {
      pathname: route
    }
  };
  beforeEach(() => {
    Auth.currentSession = jest.fn().mockImplementation(
      () => {
        return new Promise((resolve) => resolve({...})
      );
    });
  });

  afterEach(cleanup);

  it('should take a snapshot and match it', (done) => {
    let mockUseEffect = jest.spyOn(React, 'useEffect');
    const { asFragment } = render(
      <Router history={history}>
        <Home />
            </Router>
        );

        expect(asFragment(<Router history={history}>
        <Home />
    done();
  });

  it('renders without errors', (done) => {
    const { getByTestId } =  render(
      <Router history={history}>
        <Home />
      </Router>
    );

    expect(getByTestId('event-index-title')).toHaveTextContent('All Events');
    done();
  });
});

index.js

import React, { useState, useEffect } from "react";
import {
  Layout,
  Row,
  Table,
  Button,
  Modal,
  Select,
  Steps,
  message,
} from "antd";
import { withRouter } from "react-router-dom";
import EventForm from "./EventForm";
import { getAllEvents, getAggregatedEvents } from "../../apis";
import spinner from "../helpers/spinner";
import * as moment from "moment";

const { Sider } = Layout;
const { Option } = Select;
const { Step } = Steps;

const Events = (props) => {
  const [expId] = useState("abc_123");
  const [events, setEvents] = useState([]);
  const [aggregatedEvents, setAggregatedEvents] = useState([]);
  const [selectedEvent, setSelectedEvent] = useState({ venue: {} });
  const [currentStep, setCurrentStep] = useState(0);
  const [isFetching, setIsFetching] = useState(true);
  const [showAddModal, setShowAddModal] = useState(false);

  useEffect(() => {
    (async function fetchData() {
      await getAllEvents(expId)
        .then((events) => setEvents(events))
        .catch((err) => message.error("Error retrieving Events"))
        .finally(() => setIsFetching(false));

      await getAggregatedEvents(expId)
        .then((events) =>
          setAggregatedEvents(events.sort((a, b) => a.weekId - b.weekId))
        )
        .catch((err) => message.error("Error retrieving aggregated Events"));
    })();
  }, [expId]);

  const handleCancel = (e) => {
    setShowAddModal(false);
  };

  const sider = (
    <Sider
      width={210}
      style={{
        background: "#fff",
        padding: "1em",
      }}
    >
      <Button
        type="primary"
        data-testid="add-btn"
        onClick={() => {
          setSelectedEvent({ venue: {} });
          setShowAddModal(true);
        }}
      >
        + Add Event
      </Button>
    </Sider>
  );

  const columns = [
    {
      title: "Event Category",
      dataIndex: "eventCategory",
      key: "event.eventCategory",
      sorter: (a, b) => a.eventCategory.localeCompare(b.eventCategory),
    },
    {
      title: "Event Title",
      dataIndex: "eventTitle",
      key: "event.eventTitle",
      sorter: (a, b) => a.eventTitle.localeCompare(b.eventTitle),
    },
    {
      title: "Event Start Date",
      dataIndex: "eventStartDateUTC",
      key: "event.eventStartDateUTC",
      render: (text) =>
        text && text.length > 0 ? moment(text).format("MM/DD/YYYY") : "",
      defaultSortOrder: "descend",
      sorter: (a, b) =>
        moment(a.eventStartDateUTC) - moment(b.eventStartDateUTC),
      sortDirections: ["descend", "ascend"],
    },
    {
      title: "Description",
      dataIndex: "eventCaption",
      key: "event.eventCaption",
    },
  ];

  const steps = [
    {
      title: "Select Event",
      content: (
        <div>
          <Row>
            <Select
              data-testid="select-event"
              showSearch
              style={{ width: 800 }}
              placeholder="Select an event"
              optionFilterProp="children"
              filterOption={(input, option) =>
                option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
              }
              size="large"
              onChange={(val) => {
                setSelectedEvent(
                  aggregatedEvents.filter((evt) => evt.id === val)[0]
                );
                setCurrentStep(1);
              }}
            >
              {aggregatedEvents.map((evt) => (
                <Option
                  key={`${evt.id}`}
                  value={`${evt.id}`}
                >{`Week ${evt.weekId} - ${evt.homeTeam.fullName} vs ${evt.awayTeam.fullName}`}</Option>
              ))}
            </Select>
          </Row>
        </div>
      ),
    },
    {
      title: "Save Event",
      content: (
        <EventForm
          data={selectedEvent}
          isAddingEvent={true}
          closeModal={handleCancel}
        />
      ),
    },
  ];

  return (
    <div>
      <Layout.Content
        style={{
          background: "#fff",
          minHeight: 280,
          borderRadius: 7,
          color: "black",
        }}
      >
        <h2
          data-testid="event-index-title"
          style={{
            width: "100%",
            backgroundColor: "#F7F7F7",
            color: "#334D66",
            height: "50px",
            lineHeight: "50px",
            paddingLeft: "30px",
          }}
        >
          All Events
        </h2>
        <Layout>
          {sider}
          <Layout>
            <Table
              dataSource={events}
              columns={columns}
              rowKey="id"
              loading={{ spinning: isFetching, indicator: spinner }}
              onRow={(record) => ({
                onClick: (evt) => {
                  const currentUrl = props.location.pathname;
                  props.history.push({
                    pathname: `${currentUrl}/${record.id}`,
                  });
                },
              })}
            />
          </Layout>
        </Layout>
      </Layout.Content>
      <Modal
        title="Add an Event"
        visible={showAddModal}
        onCancel={handleCancel}
        width={880}
        footer={[]}
      >
        <Steps current={currentStep}>
          {steps.map((item) => (
            <Step key={item.title} title={item.title} />
          ))}
        </Steps>
        <br />
        {steps[currentStep].content}
      </Modal>
    </div>
  );
};

export default withRouter(Events);

1 个答案:

答案 0 :(得分:0)

呈现组件和分解RTL函数的语法可以是:

describe('<MyComponent />', () => {
    let rtl: RenderResult;

    beforeEach(() => {
        rtl = render(<MyComponent />);
    }

    test('something', () => {
        // here you can access all RTL functions on rtl object
        expect(rtl.getByText('...')).toBeTruthy();
        // ...
    })
})

如果您希望坚持使用语法:

({ getByText, getAllByTestId, ... } = render(
    <MyComponent />
));

// then in test
expect(getByext('...')).toBeTruthy();