Skip to content

Commit

Permalink
Merge branch '@tjzel/plugin/context-objects' into @tjzel/plugin/classes
Browse files Browse the repository at this point in the history
  • Loading branch information
tjzel committed Jul 17, 2024
2 parents 3a61e84 + 5f5920f commit b2b6a13
Show file tree
Hide file tree
Showing 34 changed files with 2,479 additions and 1,124 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import { View, TouchableOpacity, StyleSheet, Text } from 'react-native';
import { View, StyleSheet, Text, Pressable } from 'react-native';
import type { ReactNode } from 'react';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { runTests, configure } from './RuntimeTestsApi';
import { RenderLock } from './SyncUIRunner';

interface ImportButton {
testSuiteName: string;
importTest: () => void;
skipByDefault?: boolean;
}

let renderLock: RenderLock = new RenderLock();
export class ErrorBoundary extends React.Component<
{ children: React.JSX.Element | Array<React.JSX.Element> },
{ hasError: boolean }
Expand All @@ -34,77 +27,51 @@ export class ErrorBoundary extends React.Component<
}
}

function ImportButtons({ importButtons }: { importButtons: Array<ImportButton> }) {
const [importedTests, setImportedTests] = useState<Array<string>>([]);
const [importedAll, setImportedAll] = useState(false);

const handleImportAllClick = () => {
setImportedAll(true);
const newImportedTests = importedTests;
for (const button of importButtons) {
if (!button.skipByDefault) {
button.importTest();
if (!importedTests.includes(button.testSuiteName)) {
newImportedTests.push(button.testSuiteName);
}
}
}
setImportedTests(newImportedTests);
};
let renderLock: RenderLock = new RenderLock();

const handleImportClick = (button: ImportButton) => {
button.importTest();
if (!importedTests.includes(button.testSuiteName)) {
setImportedTests([...importedTests, button.testSuiteName]);
}
};
return (
<View>
<TouchableOpacity
onPress={handleImportAllClick}
style={[styles.importButton, styles.importAllButton, importedAll ? styles.importButtonImported : {}]}>
<Text style={styles.buttonText}>Import all reanimated tests</Text>
</TouchableOpacity>

<View style={styles.importButtonsFrame}>
{importButtons.map(importButton => {
const { testSuiteName } = importButton;
return (
<TouchableOpacity
key={testSuiteName}
onPress={() => handleImportClick(importButton)}
style={[styles.importButton, importedTests.includes(testSuiteName) ? styles.importButtonImported : {}]}>
<Text style={styles.buttonText}>{testSuiteName}</Text>
</TouchableOpacity>
);
})}
</View>
</View>
);
interface TestData {
testSuiteName: string;
importTest: () => void;
skipByDefault?: boolean;
}

export default function RuntimeTestsRunner({ importButtons }: { importButtons: Array<ImportButton> }) {
interface RuntimeTestRunnerProps {
tests: TestData[];
}

export default function RuntimeTestsRunner({ tests }: RuntimeTestRunnerProps) {
const [component, setComponent] = useState<ReactNode | null>(null);
const [started, setStarted] = useState<boolean>(false);
const testSelectionCallbacks = useRef<Set<() => void>>(new Set());
useEffect(() => {
if (renderLock) {
renderLock.unlock();
}
}, [component]);

async function run() {
renderLock = configure({ render: setComponent });
await runTests();
}

function handleStartClick() {
testSelectionCallbacks.current.forEach(callback => callback());
setStarted(true);
// eslint-disable-next-line no-void
void run();
}

return (
<View style={styles.container}>
{started ? null : <ImportButtons importButtons={importButtons} />}
{started ? null : (
<TouchableOpacity
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onPress={async () => {
setStarted(true);
renderLock = configure({ render: setComponent });
await runTests();
}}
style={styles.button}>
<Text style={styles.buttonTextWhite}>Run tests</Text>
</TouchableOpacity>
{started ? (
<Text style={styles.reloadText}>Reload the app to run the tests again</Text>
) : (
<>
<TestSelector tests={tests} testSelectionCallbacks={testSelectionCallbacks} />
<Pressable onPressOut={handleStartClick} style={styles.button}>
<Text style={styles.buttonTextWhite}>Run tests</Text>
</Pressable>
</>
)}

{/* Don't render anything if component is undefined to prevent blinking */}
Expand All @@ -113,23 +80,142 @@ export default function RuntimeTestsRunner({ importButtons }: { importButtons: A
);
}

interface TestSelectorProps {
tests: Array<TestData>;
testSelectionCallbacks: React.RefObject<Set<() => void>>;
}

function TestSelector({ tests, testSelectionCallbacks }: TestSelectorProps) {
const [selectedTests, setSelectedTests] = useState<Map<string, boolean>>(
tests.reduce((acc, testData) => {
acc.set(testData.testSuiteName, !testData.skipByDefault);
return acc;
}, new Map<string, boolean>()),
);

function selectAllClick(select: boolean) {
tests.forEach(button => {
setSelectedTests(selectedTests => new Map(selectedTests.set(button.testSuiteName, select)));
if (select) {
testSelectionCallbacks.current!.add(button.importTest);
} else {
testSelectionCallbacks.current!.delete(button.importTest);
}
});
}

function selectClick(button: TestData) {
setSelectedTests(new Map(selectedTests.set(button.testSuiteName, !selectedTests.get(button.testSuiteName))));
if (testSelectionCallbacks.current!.has(button.importTest)) {
testSelectionCallbacks.current!.delete(button.importTest);
} else {
testSelectionCallbacks.current!.add(button.importTest);
}
}

return (
<View>
<SelectAllButtonProps handleSelectAllClick={selectAllClick} select={true} />
<SelectAllButtonProps handleSelectAllClick={selectAllClick} select={false} />

<View style={styles.selectButtonsFrame}>
{tests.map(testData => {
return (
<SelectTest
key={testData.testSuiteName}
testSuiteName={testData.testSuiteName}
selectClick={() => selectClick(testData)}
selectedTests={selectedTests}
/>
);
})}
</View>
</View>
);
}

interface SelectTestProps {
testSuiteName: string;
selectClick: () => void;
selectedTests: Map<string, boolean>;
}

function SelectTest({ testSuiteName, selectClick, selectedTests }: SelectTestProps) {
const [isPressed, setIsPressed] = useState<boolean>(false);

function handleSelectClickIn() {
setIsPressed(true);
}

function handleSelectClickOut() {
selectClick();
setIsPressed(false);
}

return (
<Pressable
style={[styles.buttonWrapper, isPressed ? styles.pressedButton : {}]}
onPressIn={() => handleSelectClickIn()}
onPressOut={() => handleSelectClickOut()}>
<View style={[styles.checkbox, selectedTests.get(testSuiteName) ? styles.checkedCheckbox : {}]} />
<View style={styles.selectButton}>
<Text style={styles.buttonText}>{testSuiteName}</Text>
</View>
</Pressable>
);
}

interface SelectAllButtonProps {
handleSelectAllClick: (select: boolean) => void;
select: boolean;
}

function SelectAllButtonProps({ handleSelectAllClick, select }: SelectAllButtonProps) {
const [isPressed, setIsPressed] = useState<boolean>(false);

function handleSelectAllClickIn() {
setIsPressed(true);
}

function handleSelectAllClickOut() {
handleSelectAllClick(select);
setIsPressed(false);
}

return (
<Pressable
onPressIn={handleSelectAllClickIn}
onPressOut={() => handleSelectAllClickOut()}
style={[styles.selectAllButton, isPressed ? styles.pressedButton : {}]}>
<Text style={styles.buttonText}>{select ? 'Select all' : 'Deselect all'}</Text>
</Pressable>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
importAllButton: {
selectAllButton: {
marginVertical: 5,
marginHorizontal: 20,
marginTop: 20,
height: 40,
borderWidth: 2,
borderRadius: 10,
backgroundColor: 'white',
borderColor: 'navy',
justifyContent: 'center',
alignItems: 'center',
},
importButtonsFrame: {
selectButtonsFrame: {
borderRadius: 10,
backgroundColor: 'lightblue',
margin: 20,
paddingHorizontal: 40,
paddingHorizontal: 10,
paddingVertical: 10,
},
importButton: {
selectButton: {
height: 40,
borderWidth: 2,
marginVertical: 5,
Expand All @@ -138,15 +224,14 @@ const styles = StyleSheet.create({
borderColor: 'navy',
justifyContent: 'center',
alignItems: 'center',
},
importButtonImported: {
backgroundColor: 'pink',
flex: 1,
},
button: {
height: 40,
backgroundColor: 'navy',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
},
buttonText: {
fontSize: 20,
Expand All @@ -156,4 +241,30 @@ const styles = StyleSheet.create({
fontSize: 20,
color: 'white',
},
buttonWrapper: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 10,
},
checkbox: {
width: 20,
height: 20,
marginRight: 10,
borderWidth: 2,
backgroundColor: 'white',
},
checkedCheckbox: {
backgroundColor: 'navy',
},
reloadText: {
fontSize: 20,
color: 'navy',
alignSelf: 'center',
},
pressedButton: {
zIndex: 2,
backgroundColor: '#FFFA',
borderRadius: 10,
borderColor: '#FFFF',
},
});
Loading

0 comments on commit b2b6a13

Please sign in to comment.