playwright/tests/assets/reading-list/react18.html
João Neves 7e6e5f0706
feat: Support React forwards refs and memo (#23262)
This PR fixes the react selector behavior to support components that are
wrapped by the memo or forwardRef React builtin functions.

Previously these components couldn't be selected. This PR fixes that
behavior, enabling selecting those components.

Current behavior:
```
const Foo = memo(() => <div id="foo_component" />);
Foo.displayName = "Foo";
...
playwright.$("_react=Foo") -> undefined
```

Fixed behavior:
```
const Foo = memo(() => <div id="foo_component" />);
Foo.displayName = "Foo";
...
playwright.$("_react=Foo") -> <div id ="foo_component" />
```
2023-05-30 17:14:47 -07:00

114 lines
2.6 KiB
HTML

<link rel=stylesheet href='./style.css'>
<script src="./react_18.1.0.js"></script>
<script src="./react-dom_18.1.0.js"></script>
<div id=root></div>
<script>
const e = React.createElement;
function AppHeader(props) {
return e(React.Fragment, null,
e('h1', null, `reactjs@${React.version}`),
e('h3', null, `Reading List: ${props.bookCount}`),
);
}
class NewBook extends React.Component {
constructor(props) {
super(props);
this.state = '';
}
onInput(event) {
this.state = event.target.value;
}
render() {
return e(React.Fragment, null,
e('input', {onInput: this.onInput.bind(this)}, null),
e('button', {
onClick: () => this.props.onNewBook(this.state),
}, `new book`),
);
}
}
function ColorButton (props) {
return e('button', {className: props.color, disabled: !props.enabled}, 'button ' + props.nested.index);
}
const ButtonGrid = React.memo(function() {
const buttons = [];
for (let i = 0; i < 9; ++i) {
buttons.push(e(ColorButton, {
color: ['red', 'green', 'blue'][i % 3],
enabled: i % 2 === 0,
nested: {
index: i,
value: i + 0.1,
}
}, null));
};
return e(React.Fragment, null, ...buttons);
});
ButtonGrid.displayName = "ButtonGrid";
class BookItem extends React.Component {
render() {
return e('div', null, this.props.name);
}
}
class BookList extends React.Component {
render() {
return e('ol', null, this.props.books.map(book => e('li', {key: book.name}, e(BookItem, { name: book.name }))));
}
}
const apps = [];
class App extends React.Component {
constructor(props) {
super(props);
apps.push(this);
this.mountPoint = React.createRef();
this.state = {
books: [
{name: 'Pride and Prejudice' },
{name: 'To Kill a Mockingbird' },
{name: 'The Great Gatsby' },
],
};
}
render() {
return e(React.Fragment, null,
e(AppHeader, {bookCount: this.state.books.length}, null),
e(NewBook, {onNewBook: bookName => this.onNewBook(bookName)}, null),
e(BookList, {books: this.state.books}, null),
e(ButtonGrid, null, null),
e('div', {ref: this.mountPoint}, null),
);
}
onNewBook(bookName) {
this.setState({
books: [...this.state.books, {name: bookName}],
});
}
}
{
window.mountApp = element => {
const root = ReactDOM.createRoot(element);
root.render(e(App, null, null));
return root;
};
window.mountApp(document.getElementById('root'));
window.mountNestedApp = () => window.mountApp(apps[apps.length - 1].mountPoint.current);
}
</script>