Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page Object Pattern を React Component テストでも利用する #829

Open
tomoyukikashiro opened this issue Aug 13, 2022 · 0 comments
Open

Comments

@tomoyukikashiro
Copy link
Owner

tomoyukikashiro commented Aug 13, 2022


date: 2022-08-13
title: Page Object Pattern を React Component テストでも利用する
summary: E2E テストで利用する Page Object Pattern を Component テストでも利用することで可読性の高いテストがかけるのではないだろうか?
slug: page-object-pattern-in-react-component-tests
lang: ja-JP
tags:


E2E テストで利用する Page Object Pattern を Component テストでも利用することで可読性の高いテストがかけるのではないだろうかと思ってメモに残します。

Page Object Pattern とは

https://webdriver.io/docs/pageobjects/

E2E テストでは、以下2つのコードが混在することになり、テストがしたいことがぱっと見でわかりにくいことがあります。

  • テストコード(例:フォームにinvalidなemailが入力されている場合、エラーが表示すること
  • テストするためにページを操作するコード(例:フォームに文字を入力または、フォームのエラー文字を取得)

さらに、 テストするためにページを操作するコード が点在していると、フォームの id や name を修正しただけで、点在するコードをすべて修正することになりメンテナンス性も損なわれがちです。

Page Object Pattern では、テストするためにページを操作するコード を オブジェクトでひとまとめにして、使い回すことで、テストの可読性やメンテナンス性を上げる方法です。

Page Object Pattern の例

https://webdriver.io/docs/pageobjects/ の例をそのまま利用すると、、

// selenium など E2E テストライブのインスタンスを保持する親クラス
import Page from './page'

class LoginPage extends Page {

    // ログインページのテストで使う `テストするためにページを操作するコード`
    get username () { return $('#username') }
    get password () { return $('#password') }
    get submitBtn () { return $('form button[type="submit"]') }
    get flash () { return $('#flash') }
    get headerLinks () { return $$('#header a') }

    async open () {
        await super.open('login')
    }

    async submit () {
        await this.submitBtn.click()
    }

}

export default new LoginPage()

これを、テストコードで使いまわしますことで、 テストするためにページを操作するコード がシンプルになり、テストコードが読みやすく、またページに変更があっても Page Object を修正するだけで済み、テストコードへの影響を抑えることができます。

it('should deny access with wrong creds', async () => {
    await LoginPage.open()
    await LoginPage.username.setValue('foo')
    await LoginPage.password.setValue('bar')
    await LoginPage.submit()

    await expect(LoginPage.flash).toHaveText('Your username is invalid!')
})

React Component テストで Page Object Pattern を 利用する

import type { ComponentProps } from "react";
import { render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import LoginForm from "./LoginForm";

type Props = ComponentProps<typeof LoginForm>

const setup = (props): Props => {
  const { getByRole, getByLabelText, getByText } = render(<LoginForm {...props} />);
  return {
    typeEmail: (email: string) => userEvent.type(getByLabelText("email"), email),
    getByText,
    submit: () => userEvent.click(getByRole("button"))
  };
};


it("invalidなemailの場合、エラーを表示する。", () => {
  const utils = setup();
  utils.typeEmail("invalidemail");
  utils.submit();

  expect(utils.getByText("Emailが正しくありません。")). toBeInTheDocument();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant