-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Allen Zhang (张涛)
committed
Mar 4, 2024
1 parent
7591fcc
commit bbe7d59
Showing
21 changed files
with
542 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.DS_Store | ||
/node_modules | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const {chromium} = require('playwright'); | ||
const main = async () => { | ||
const browser = await chromium.launch() | ||
const page = await browser.newPage(); | ||
// 进入被测页面 | ||
await page.goto('http://test.com') | ||
// 执行测试用例 | ||
// 用例1 | ||
await page.click('button') | ||
// 用例2 | ||
await page.fill('input', 'test') | ||
// 用例3 | ||
await page.click('text=submit') | ||
const coverage = await page.evaluate(`window.__coverage__`) | ||
console.log(coverage) | ||
browser.close() | ||
} | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "play-write", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "node ./main.js" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"playwright": "^1.42.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"extends": ["eslint:recommended", "plugin:react/recommended"], | ||
"settings": { | ||
"react": { | ||
"version": "17.0.2" | ||
} | ||
}, | ||
"rules": { | ||
"no-extra-parens": 0, | ||
"react/prop-types": 0, | ||
"react/react-in-jsx-scope": 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.DS_Store | ||
/node_modules | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports={ | ||
plugins: ['istanbul'] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ | ||
"name": "todomvc-react", | ||
"version": "1.0.0", | ||
"description": "A TodoMVC written in React.", | ||
"private": true, | ||
"engines": { | ||
"node": ">=18.13.0", | ||
"npm": ">=8.19.3" | ||
}, | ||
"scripts": { | ||
"build": "webpack --config webpack.prod.js", | ||
"dev": "webpack serve --open --config webpack.dev.js", | ||
"serve": "http-server ./dist -p 7002 -c-1 --cors", | ||
"test": "jest" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.24.0", | ||
"@babel/preset-env": "^7.24.0", | ||
"@babel/preset-react": "^7.23.3", | ||
"babel-loader": "^9.1.3", | ||
"babel-plugin-istanbul": "^6.1.1", | ||
"css-loader": "^6.10.0", | ||
"css-minimizer-webpack-plugin": "^4.2.2", | ||
"eslint-plugin-react": "^7.34.0", | ||
"html-webpack-plugin": "^5.6.0", | ||
"http-server": "^14.1.1", | ||
"mini-css-extract-plugin": "^2.8.1", | ||
"style-loader": "^3.3.4", | ||
"webpack": "^5.90.3", | ||
"webpack-cli": "^5.1.4", | ||
"webpack-dev-server": "^4.15.1", | ||
"webpack-merge": "^5.10.0" | ||
}, | ||
"dependencies": { | ||
"classnames": "^2.5.1", | ||
"react": "^17.0.2", | ||
"react-dom": "^17.0.2", | ||
"react-router-dom": "^6.22.2", | ||
"todomvc-app-css": "^2.4.3", | ||
"todomvc-common": "^1.0.5" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<!DOCTYPE html> | ||
<html lang="en" data-framework="react"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="description" content="A TodoMVC written in React." /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> | ||
<title>TodoMVC: React</title> | ||
</head> | ||
<body> | ||
<section class="todoapp" id="root"></section> | ||
<footer class="info"> | ||
<p>Double-click to edit a todo</p> | ||
<p>Created by the TodoMVC Team</p> | ||
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p> | ||
</footer> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from "react"; | ||
import { render } from "react-dom"; | ||
import { HashRouter, Route, Routes } from "react-router-dom"; | ||
|
||
import { App } from "./todo/app"; | ||
import "todomvc-app-css/index.css"; | ||
|
||
render( | ||
<HashRouter> | ||
<Routes> | ||
<Route path="*" element={<App />} /> | ||
</Routes> | ||
</HashRouter>, | ||
document.getElementById("root") | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* used for things that should be hidden in the ui, | ||
but useful for people who use screen readers */ | ||
.visually-hidden { | ||
border: 0; | ||
clip: rect(0 0 0 0); | ||
clip-path: inset(50%); | ||
height: 1px; | ||
width: 1px; | ||
margin: -1px; | ||
padding: 0; | ||
overflow: hidden; | ||
position: absolute; | ||
white-space: nowrap; | ||
} | ||
|
||
.toggle-all { | ||
width: 40px !important; | ||
height: 60px !important; | ||
right: auto !important; | ||
} | ||
|
||
.toggle-all-label { | ||
pointer-events: none; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useReducer } from "react"; | ||
import { Header } from "./components/header"; | ||
import { Main } from "./components/main"; | ||
import { Footer } from "./components/footer"; | ||
|
||
import { todoReducer } from "./reducer"; | ||
|
||
import "./app.css"; | ||
|
||
export function App() { | ||
const [todos, dispatch] = useReducer(todoReducer, []); | ||
|
||
return ( | ||
<> | ||
<Header dispatch={dispatch} /> | ||
<Main todos={todos} dispatch={dispatch} /> | ||
<Footer todos={todos} dispatch={dispatch} /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { useCallback, useMemo } from "react"; | ||
import { useLocation } from "react-router-dom"; | ||
import classnames from "classnames"; | ||
|
||
import { REMOVE_COMPLETED_ITEMS } from "../constants"; | ||
|
||
export function Footer({ todos, dispatch }) { | ||
const { pathname: route } = useLocation(); | ||
|
||
const activeTodos = useMemo(() => todos.filter((todo) => !todo.completed), [todos]); | ||
|
||
const removeCompleted = useCallback(() => dispatch({ type: REMOVE_COMPLETED_ITEMS }), [dispatch]); | ||
|
||
// prettier-ignore | ||
if (todos.length === 0) | ||
return null; | ||
|
||
return ( | ||
<footer className="footer" data-testid="footer"> | ||
<span className="todo-count">{`${activeTodos.length} ${activeTodos.length === 1 ? "item" : "items"} left!`}</span> | ||
<ul className="filters" data-testid="footer-navigation"> | ||
<li> | ||
<a className={classnames({ selected: route === "/" })} href="#/"> | ||
All | ||
</a> | ||
</li> | ||
<li> | ||
<a className={classnames({ selected: route === "/active" })} href="#/active"> | ||
Active | ||
</a> | ||
</li> | ||
<li> | ||
<a className={classnames({ selected: route === "/completed" })} href="#/completed"> | ||
Completed | ||
</a> | ||
</li> | ||
</ul> | ||
<button className="clear-completed" disabled={activeTodos.length === todos.length} onClick={removeCompleted}> | ||
Clear completed | ||
</button> | ||
</footer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { useCallback } from "react"; | ||
import { Input } from "./input"; | ||
|
||
import { ADD_ITEM } from "../constants"; | ||
|
||
export function Header({ dispatch }) { | ||
const addItem = useCallback((title) => dispatch({ type: ADD_ITEM, payload: { title } }), [dispatch]); | ||
|
||
return ( | ||
<header className="header" data-testid="header"> | ||
<h1>todos</h1> | ||
<Input onSubmit={addItem} label="New Todo Input" placeholder="What needs to be done?" /> | ||
</header> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { useCallback } from "react"; | ||
|
||
const sanitize = (string) => { | ||
const map = { | ||
"&": "&", | ||
"<": "<", | ||
">": ">", | ||
'"': """, | ||
"'": "'", | ||
"/": "/", | ||
}; | ||
const reg = /[&<>"'/]/gi; | ||
return string.replace(reg, (match) => map[match]); | ||
}; | ||
|
||
const hasValidMin = (value, min) => { | ||
return value.length >= min; | ||
}; | ||
|
||
export function Input({ onSubmit, placeholder, label, defaultValue, onBlur }) { | ||
const handleBlur = useCallback(() => { | ||
if (onBlur) | ||
onBlur(); | ||
}, [onBlur]); | ||
|
||
const handleKeyDown = useCallback( | ||
(e) => { | ||
if (e.key === "Enter") { | ||
const value = e.target.value.trim(); | ||
|
||
if (!hasValidMin(value, 2)) | ||
return; | ||
|
||
onSubmit(sanitize(value)); | ||
e.target.value = ""; | ||
} | ||
}, | ||
[onSubmit] | ||
); | ||
|
||
return ( | ||
<div className="input-container"> | ||
<input className="new-todo" id="todo-input" type="text" data-testid="text-input" autoFocus placeholder={placeholder} defaultValue={defaultValue} onBlur={handleBlur} onKeyDown={handleKeyDown} /> | ||
<label className="visually-hidden" htmlFor="todo-input"> | ||
{label} | ||
</label> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { memo, useState, useCallback } from "react"; | ||
import classnames from "classnames"; | ||
|
||
import { Input } from "./input"; | ||
|
||
import { TOGGLE_ITEM, REMOVE_ITEM, UPDATE_ITEM } from "../constants"; | ||
|
||
export const Item = memo(function Item({ todo, dispatch, index }) { | ||
const [isWritable, setIsWritable] = useState(false); | ||
const { title, completed, id } = todo; | ||
|
||
const toggleItem = useCallback(() => dispatch({ type: TOGGLE_ITEM, payload: { id } }), [dispatch]); | ||
const removeItem = useCallback(() => dispatch({ type: REMOVE_ITEM, payload: { id } }), [dispatch]); | ||
const updateItem = useCallback((id, title) => dispatch({ type: UPDATE_ITEM, payload: { id, title } }), [dispatch]); | ||
|
||
const handleDoubleClick = useCallback(() => { | ||
setIsWritable(true); | ||
}, []); | ||
|
||
const handleBlur = useCallback(() => { | ||
setIsWritable(false); | ||
}, []); | ||
|
||
const handleUpdate = useCallback( | ||
(title) => { | ||
if (title.length === 0) | ||
removeItem(id); | ||
else | ||
updateItem(id, title); | ||
|
||
setIsWritable(false); | ||
}, | ||
[id, removeItem, updateItem] | ||
); | ||
|
||
return ( | ||
<li className={classnames({ completed: todo.completed })} data-testid="todo-item"> | ||
<div className="view"> | ||
{isWritable ? ( | ||
<Input onSubmit={handleUpdate} label="Edit Todo Input" defaultValue={title} onBlur={handleBlur} /> | ||
) : ( | ||
<> | ||
<input className="toggle" type="checkbox" data-testid="todo-item-toggle" checked={completed} onChange={toggleItem} /> | ||
<label data-testid="todo-item-label" onDoubleClick={handleDoubleClick}> | ||
{title} | ||
</label> | ||
<button className="destroy" data-testid="todo-item-button" onClick={removeItem} /> | ||
</> | ||
)} | ||
</div> | ||
</li> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { useMemo, useCallback } from "react"; | ||
import { useLocation } from "react-router-dom"; | ||
|
||
import { Item } from "./item"; | ||
import classnames from "classnames"; | ||
|
||
import { TOGGLE_ALL } from "../constants"; | ||
|
||
export function Main({ todos, dispatch }) { | ||
const { pathname: route } = useLocation(); | ||
|
||
const visibleTodos = useMemo( | ||
() => | ||
todos.filter((todo) => { | ||
if (route === "/active") | ||
return !todo.completed; | ||
|
||
if (route === "/completed") | ||
return todo.completed; | ||
|
||
return todo; | ||
}), | ||
[todos, route] | ||
); | ||
|
||
const toggleAll = useCallback((e) => dispatch({ type: TOGGLE_ALL, payload: { completed: e.target.checked } }), [dispatch]); | ||
|
||
return ( | ||
<main className="main" data-testid="main"> | ||
{visibleTodos.length > 0 ? ( | ||
<div className="toggle-all-container"> | ||
<input className="toggle-all" type="checkbox" data-testid="toggle-all" checked={visibleTodos.every((todo) => todo.completed)} onChange={toggleAll} /> | ||
<label className="toggle-all-label" htmlFor="toggle-all"> | ||
Toggle All Input | ||
</label> | ||
</div> | ||
) : null} | ||
<ul className={classnames("todo-list")} data-testid="todo-list"> | ||
{visibleTodos.map((todo, index) => ( | ||
<Item todo={todo} key={todo.id} dispatch={dispatch} index={index} /> | ||
))} | ||
</ul> | ||
</main> | ||
); | ||
} |
Oops, something went wrong.