Skip to content

Commit

Permalink
Merge branch 'master' into feature/logout_functionality
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/state/ducks/front/login/api.ts
#	src/utils/OAuthApiUtils.ts
  • Loading branch information
sai-gillingham committed Sep 22, 2023
2 parents eb7b6c2 + 6cbecfe commit e8a428d
Show file tree
Hide file tree
Showing 11 changed files with 322 additions and 16 deletions.
111 changes: 111 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: E2E test for EC-CUBE
on:
push:
branches:
- '**'
tags:
- '**'
paths:
- '**'
- '!*.md'
pull_request:
paths:
- '**'
- '!*.md'
workflow_dispatch:
inputs:
eccube-api-repository:
description: 'EC-CUBE API REPOSITORY'
default: 'https://github.com/EC-CUBE/eccube-api4.git'
required: false
eccube-api-branch:
description: 'EC-CUBE API BRANCH'
default: 'next-poc'
required: false
env:
API_REPOSITORY: ${{ inputs.eccube-api-repository || 'https://github.com/EC-CUBE/eccube-api4.git' }}
API_BRANCH: ${{ inputs.eccube-api-branch || 'next-poc' }}

jobs:
e2e:
name: E2E
runs-on: ubuntu-22.04
strategy:
fail-fast: false

services:
postgres:
image: postgres:14
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

mailcatcher:
image: schickling/mailcatcher
ports:
- 1080:1080
- 1025:1025

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1

- name: Setup EC-CUBE
run: |
git clone https://github.com/EC-CUBE/next-poc.git ec-cube
cd ec-cube
composer install
echo "APP_ENV=prod
APP_DEBUG=0
TRUSTED_HOSTS=^127\.0\.0\.1$,^localhost$
DATABASE_URL=postgres://postgres:[email protected]:5432/eccube_db
DATABASE_SERVER_VERSION=14
MAILER_DSN=smtp://127.0.0.1:1025" > .env
bin/console doctrine:database:create
bin/console doctrine:schema:create
bin/console eccube:fixtures:load
- name: Setup EC-CUBE API Plugin
working-directory: ec-cube
run: |
git clone -b ${API_BRANCH} ${API_REPOSITORY}
sed -i 's/"extra": {/"extra": { "id": 123,/g' eccube-api4/composer.json
bin/console eccube:composer:require ec-cube/api42 --from=./eccube-api4
bin/console eccube:plugin:enable --code Api42
bin/console doctrine:schema:update --dump-sql -f # プラグイン有効化時に何故かoauth2のテーブルが生成されないので
bin/console doctrine:query:sql "INSERT INTO oauth2_client (name, secret, redirect_uris, grants, scopes, active, allow_plain_text_pkce, identifier) VALUES ('', NULL, 'http://localhost', 'password refresh_token', 'read:Authority write:Authority read:AuthorityRole write:AuthorityRole read:BaseInfo write:BaseInfo read:Block write:Block read:BlockPosition write:BlockPosition read:Cart write:Cart read:CartItem write:CartItem read:Category write:Category read:ClassCategory write:ClassCategory read:ClassName write:ClassName read:Country write:Country read:Csv write:Csv read:CsvType write:CsvType read:Customer write:Customer read:CustomerAddress write:CustomerAddress read:CustomerFavoriteProduct write:CustomerFavoriteProduct read:CustomerOrderStatus write:CustomerOrderStatus read:CustomerStatus write:CustomerStatus read:Delivery write:Delivery read:DeliveryDuration write:DeliveryDuration read:DeliveryFee write:DeliveryFee read:DeliveryTime write:DeliveryTime read:DeviceType write:DeviceType read:Job write:Job read:Layout write:Layout read:MailHistory write:MailHistory read:MailTemplate write:MailTemplate read:Member write:Member read:News write:News read:Order write:Order read:OrderItem write:OrderItem read:OrderItemType write:OrderItemType read:OrderPdf write:OrderPdf read:OrderStatus write:OrderStatus read:OrderStatusColor write:OrderStatusColor read:Page write:Page read:PageLayout write:PageLayout read:PageMax write:PageMax read:Payment write:Payment read:PaymentOption write:PaymentOption read:Plugin write:Plugin read:Pref write:Pref read:Product write:Product read:ProductCategory write:ProductCategory read:ProductClass write:ProductClass read:ProductImage write:ProductImage read:ProductListMax write:ProductListMax read:ProductListOrderBy write:ProductListOrderBy read:ProductStatus write:ProductStatus read:ProductStock write:ProductStock read:ProductTag write:ProductTag read:RoundingType write:RoundingType read:SaleType write:SaleType read:Sex write:Sex read:Shipping write:Shipping read:Tag write:Tag read:TaxDisplayType write:TaxDisplayType read:TaxRule write:TaxRule read:TaxType write:TaxType read:Template write:Template read:Work write:Work', true, false, '121ecaab37f52176ef2b7ce9dfca872b');"
- name: Start PHP Development Server
working-directory: ec-cube
run: |
php -S localhost:8080 &
- name: Start EC-CUBE Client
run: |
sed -i 's/<<API_CLIENT_KEY>>/121ecaab37f52176ef2b7ce9dfca872b/g' .env.development
sed -i 's|$REACT_APP_API_URL|http://localhost:8080|g' .env.development
cp .env.development .env
npm ci
echo a | node tools/EccubeReactBuilder.js
npx react-scripts start &
npx wait-on http://127.0.0.1:3000
- name: Start E2E Tests
run: |
rm -rf ec-cube/zap # ec-cube本体のplaywrightが実行されてしまうので削除
npx playwright install
npx playwright test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

# testing
/coverage
/test-results

# production
/build
Expand Down
137 changes: 137 additions & 0 deletions e2e/poc.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { test, expect } from '@playwright/test';

const crypto = require("crypto");

const CLIENT_URL = 'http://localhost:3000';
const MAILCATCHER_URL = 'http://localhost:1080';

test('pocのシナリオをテストする', async ({ page }) => {
await page.goto(CLIENT_URL);

const params = {
'email': 'ec-cube+' + crypto.randomBytes(3).toString('hex') + '@example.com',
'password': 'password.1234'
}

// 会員登録
await entry(page, params)

// 本会員登録
await entry_activate(page, params);

// ログイン
await login(page, params)

// 購入フロー
await purchase(page, params)

// ログアウト
// await logout(page)

// 404
await not_found(page, params)
});

async function entry(page, params) {
// 会員登録画面を表示
await page.locator('text=登録').click()
await expect(page.url()).toBe(CLIENT_URL + '/entry');
// 入力
await page.getByLabel('名前「姓」 *').fill('足立');
await page.getByLabel('名前「名」 *').fill('智広');
await page.getByLabel('フリガナ「セイ」 *').fill('あだち');
await page.getByLabel('フリガナ「メイ」 *').fill('ちひろ');
await page.getByTestId('address_pref').click();
await page.getByRole('option', { name: '北海道' }).click();
await page.getByLabel('郵便番号 *').fill('0001111');
await page.getByLabel('住所「市区町村名」 *').fill('住所1');
await page.getByLabel('住所「番地・ビル名」 *').fill('住所2');
await page.getByLabel('電話番号 *').fill('00011112222');
await page.getByLabel('メールアドレス *').fill(params.email);
await page.getByLabel('パスワード *').fill(params.password);
// 送信
await page.getByRole('button', { name: '送信' }).click();
const thanks = await page.getByText('仮会員登録は完了しています。');
await expect(thanks).toBeVisible();
await expect(page.url()).toBe(CLIENT_URL + '/entry/complete');
}

async function entry_activate(page, params) {
// mailcatcherから最後のメッセージを取得
const messagesResp = await fetch(MAILCATCHER_URL + '/messages');
const messages = await messagesResp.json();
const id = messages.pop().id;

// mail bodyから本会員登録用URLを取得
const bodyResp = await fetch(MAILCATCHER_URL + '/messages/' + id + '.plain');
const body = await bodyResp.text();
const activate_url = body.match(/http.+/)[0]

// 本会員登録用URLを表示
await page.goto(activate_url);
const thanks = await page.getByText('会員登録ありがとうございます');
await expect(thanks).toBeVisible();

// ec-cube clientへ戻る
await page.goto(CLIENT_URL);
}

async function login(page, params) {
await page.getByRole('link', {name: 'ログイン'}).getByRole('button').click();
await expect(page.url()).toBe(CLIENT_URL + '/mypage/login');

let token = await page.locator('text=現在のセッショントークン');
await expect(token).toContainText('未ログイン');

await page.getByLabel('ユーザー名 *').fill(params.email);
await page.getByLabel('パスワード *').fill(params.password);
await page.getByRole('button', {name: '送信'}).click();

token = await page.locator('text=現在のセッショントークン');
await expect(token).not.toContainText('未ログイン');
}

// todo
async function logout(page) {

}

async function purchase(page, params) {
// 商品詳細を表示
await page.getByRole('button', { name: '購入' }).click();
await expect(page.url()).toBe(CLIENT_URL + '/product/detail/2');
await page.getByText("チェリーアイスサンド");
// カートに入れる
await page.getByRole('button', { name: 'カートに追加' }).click();
// カートアイコンをクリック
await page.getByLabel('account of current user').click();
// カート表示
await page.getByRole('button', { name: 'カートを見る' }).click();
await expect(page.url()).toBe(CLIENT_URL + '/cart');
await page.getByTestId('CloseIcon').locator('path').click(); // サイドバーをクローズ
// 注文画面へ
await page.getByRole('button', { name: 'レジへ進む' }).click();
await expect(page.url()).toBe(CLIENT_URL + '/shopping');
// 支払い方法を変更
await page.getByText('お支払い情報').waitFor({state: "visible"});
const paymentInput = await page.getByText('代金引換');
await expect(paymentInput).toBeVisible();
await page.waitForTimeout(1000); // 支払い方法のクリックが検知されないため少しだけ待機
await paymentInput.click();
// 確認画面へ
await page.getByRole('button', { name: '確認する' }).click();
await expect(page.url()).toBe(CLIENT_URL + '/shopping/confirm');
const paymentConfirm = await page.getByText('代金引換');
await expect(paymentConfirm).toBeVisible();
// 注文完了
await page.getByRole('button', { name: '注文する' }).click();
const thanks = await page.getByText('注文ありがとうございます。');
await expect(thanks).toBeVisible();
await expect(page.url()).toBe(CLIENT_URL + '/shopping/complete');
}

async function not_found(page, params) {
await page.goto(CLIENT_URL + '/product/detail/999')
const not_found = await page.getByText('404');
await expect(not_found).toBeVisible();
}
40 changes: 37 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@playwright/test": "^1.37.1"
}
}
6 changes: 4 additions & 2 deletions src/state/ducks/front/cart/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ export function modifyCartProduct(access_token: string, product_class_id: number
return new GraphQLUtils(access_token).sendMutation(
cartMutations.MODIFY_CART_MUTATION,
{
product_class_id: product_class_id,
quantity: quantity
input: {
product_class_id: product_class_id,
quantity: quantity
},
}
)
}
Expand Down
6 changes: 2 additions & 4 deletions src/state/ducks/front/cart/graphql/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import {gql} from "@apollo/client";

const MODIFY_CART_MUTATION = gql`
mutation cartModify(
$product_class_id: ID!
$quantity: Int!
$input: add_cartInput!
) {
cartModify(
product_class_id: $product_class_id,
quantity: $quantity
input: $input
) {
id
}
Expand Down
4 changes: 2 additions & 2 deletions src/translations/jp/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"postal_code": "郵便番号",
"pref": "都道府県",
"address": {
"addr01": "住所「都道府県",
"addr02": "住所「市区町村"
"addr01": "住所「市区町村名",
"addr02": "住所「番地・ビル名"
},
"email": {
"first": "メールアドレス",
Expand Down
2 changes: 1 addition & 1 deletion src/utils/OAuthApiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default class OAuthApiUtils {
* @param {string|null} baseurl カスタムURL
*/
constructor(timeout = null, baseurl = null) {
axios.defaults.baseURL = baseurl || 'http://localhost:8080';
axios.defaults.baseURL = baseurl || process.env.REACT_APP_API_URL;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.timeout = timeout || process.env.REACT_APP_ECCUBE_TIMEOUT;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const ProductDetailComponent = (
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<img
src={"http://localhost:8080/html/upload/save_image/" + productDetail?.ProductImage?.[0]?.file_name}
src={process.env.REACT_APP_API_URL + "/html/upload/save_image/" + productDetail?.ProductImage?.[0]?.file_name}
alt={productDetail.name}/>
</Grid>
<Grid item xs={12} sm={6}>
Expand Down
Loading

0 comments on commit e8a428d

Please sign in to comment.