mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-05 22:56:11 +00:00
<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please follow the template so that the reviewers can easily understand what the code changes affect --> # Summary This PR adds E2E tests based on view screenshots done via `react-native-view-shot`. It only works with devices that have their [pixel ratio](https://reactnative.dev/docs/pixelratio) equal `3`. If you want to use device with different pixel ratio, you need to adjust it in `e2e/generateReferences.ts` viewport and regenerate reference images (see below). Steps to run tests: - Run Metro server for example app via `yarn start` in example app's directory - Run `example` app on platform of your choice (currently only Android & iOS are supported) via `yarn android` or `yarn ios` in example app's directory - Run `yarn e2e` in project's root directory to start Jest server - Select `E2E` tab in example app - Wait for tests to finish - You can see test results, as well as diffs (actual rendered svg vs reference image) in `e2e/diffs` directory Steps to add new test cases: - Put SVG of your choice to `e2e/cases` directory - Run `yarn generateE2eRefrences`, this will open headless chrome browser via `puppeteer` and snapshot all rendered SVGs to .png files and later use them as reference in tests - You should see new .png files in `e2e/references` - When you run E2E tests again, it will use new test case(s) you've added ## Test Plan https://github.com/software-mansion/react-native-svg/assets/41289688/24ee5447-ce9a-43b6-9dde-76229d25a30a https://github.com/software-mansion/react-native-svg/assets/41289688/71d1873f-8155-4494-80bd-e4c1fa72a065 ### What's required for testing (prerequisites)? See Summary ### What are the steps to reproduce (after prerequisites)? See Summary ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ | | Web | ❌ | ## Checklist <!-- Check completed item, when applicable, via: [X] --> - [X] I have tested this on a device and a simulator - [x] I added documentation in `README.md` - [X] I updated the typed files (typescript) - [X] I added a test for the API in the `__tests__` folder --------- Co-authored-by: bohdanprog <bohdan.artiukhov@swmansion.com> Co-authored-by: Jakub Grzywacz <jakub.grzywacz@swmansion.com>
186 lines
4.5 KiB
TypeScript
186 lines
4.5 KiB
TypeScript
/**
|
|
* Sample React Native App for react-native-svg library
|
|
* https://github.com/magicismight/react-native-svg/tree/master/Example
|
|
*/
|
|
'use strict';
|
|
|
|
import React, {Component} from 'react';
|
|
import {
|
|
Dimensions,
|
|
Modal,
|
|
Platform,
|
|
SafeAreaView,
|
|
ScrollView,
|
|
StyleSheet,
|
|
Text,
|
|
TouchableHighlight,
|
|
TouchableOpacity,
|
|
View,
|
|
} from 'react-native';
|
|
import {Circle, Line, Svg} from 'react-native-svg';
|
|
|
|
import {commonStyles} from './src/commonStyles';
|
|
import E2eTestingView from './src/e2e';
|
|
import * as examples from './src/examples';
|
|
import {names} from './utils/names';
|
|
|
|
const initialState = {
|
|
modal: false,
|
|
content: null,
|
|
};
|
|
|
|
export default class SvgExample extends Component {
|
|
state: {
|
|
content: React.ReactNode;
|
|
modal: boolean;
|
|
scroll?: boolean;
|
|
} = initialState;
|
|
|
|
show = (name: keyof typeof examples) => {
|
|
if (this.state.modal) {
|
|
return;
|
|
}
|
|
let example = examples[name];
|
|
if (example) {
|
|
let samples = example.samples;
|
|
this.setState({
|
|
modal: true,
|
|
content: (
|
|
<View>
|
|
{samples.map((Sample, i) => (
|
|
<View style={commonStyles.example} key={`sample-${i}`}>
|
|
<Text style={commonStyles.sampleTitle}>{Sample.title}</Text>
|
|
<Sample />
|
|
</View>
|
|
))}
|
|
</View>
|
|
),
|
|
scroll: (example as {scroll?: boolean}).scroll !== false,
|
|
});
|
|
}
|
|
};
|
|
|
|
hide = () => {
|
|
this.setState(initialState);
|
|
};
|
|
|
|
getExamples = () => {
|
|
return names
|
|
.filter(el => {
|
|
if (el !== 'E2E') return true;
|
|
return Platform.OS === 'android' || Platform.OS === 'ios';
|
|
})
|
|
.map(name => {
|
|
var icon;
|
|
let example = examples[name as keyof typeof examples];
|
|
if (example) {
|
|
icon = example.icon;
|
|
}
|
|
return (
|
|
<TouchableHighlight
|
|
style={styles.link}
|
|
underlayColor="#ccc"
|
|
key={`example-${name}`}
|
|
onPress={() => this.show(name as keyof typeof examples)}>
|
|
<View style={commonStyles.cell}>
|
|
{icon}
|
|
<Text style={commonStyles.title}>{name}</Text>
|
|
</View>
|
|
</TouchableHighlight>
|
|
);
|
|
});
|
|
};
|
|
|
|
modalContent = () => (
|
|
<>
|
|
<SafeAreaView style={{flex: 1}}>
|
|
<ScrollView
|
|
style={styles.scroll}
|
|
contentContainerStyle={styles.scrollContent}
|
|
scrollEnabled={this.state.scroll}>
|
|
{this.state.content}
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
<SafeAreaView style={styles.close}>
|
|
<TouchableOpacity activeOpacity={0.7} onPress={this.hide}>
|
|
<Svg height="20" width="20">
|
|
<Circle cx="10" cy="10" r="10" fill="red" />
|
|
<Line x1="4" y1="4" x2="16" y2="16" stroke="#fff" strokeWidth="2" />
|
|
<Line x1="4" y1="16" x2="16" y2="4" stroke="#fff" strokeWidth="2" />
|
|
</Svg>
|
|
</TouchableOpacity>
|
|
</SafeAreaView>
|
|
</>
|
|
);
|
|
|
|
render() {
|
|
if (process.env.E2E) {
|
|
console.log(
|
|
'Opening E2E example, as E2E env is set to ' + process.env.E2E,
|
|
);
|
|
return <E2eTestingView />;
|
|
}
|
|
return (
|
|
<SafeAreaView style={styles.container}>
|
|
<Text style={commonStyles.welcome}>SVG library for React Apps</Text>
|
|
<View style={styles.contentContainer}>{this.getExamples()}</View>
|
|
{(Platform.OS === 'windows' || Platform.OS === 'macos') &&
|
|
this.state.modal ? (
|
|
<View style={styles.scroll}>{this.modalContent()}</View>
|
|
) : (
|
|
<Modal
|
|
transparent={false}
|
|
animationType="fade"
|
|
visible={this.state.modal}
|
|
onRequestClose={this.hide}>
|
|
{this.modalContent()}
|
|
</Modal>
|
|
)}
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
}
|
|
|
|
const hairline = StyleSheet.hairlineWidth;
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
paddingTop: 20,
|
|
alignItems: 'center',
|
|
overflow: 'hidden',
|
|
},
|
|
contentContainer: {
|
|
alignSelf: 'stretch',
|
|
borderTopWidth: hairline,
|
|
borderTopColor: '#ccc',
|
|
borderBottomWidth: hairline,
|
|
borderBottomColor: '#ccc',
|
|
flexWrap: 'wrap',
|
|
flexDirection: 'row',
|
|
marginHorizontal: 10,
|
|
},
|
|
link: {
|
|
height: 40,
|
|
alignSelf: 'stretch',
|
|
width: Dimensions.get('window').width / 2 - 10,
|
|
},
|
|
close: {
|
|
position: 'absolute',
|
|
right: 20,
|
|
top: 20,
|
|
},
|
|
scroll: {
|
|
position: 'absolute',
|
|
top: 30,
|
|
right: 10,
|
|
bottom: 20,
|
|
left: 10,
|
|
backgroundColor: '#fff',
|
|
},
|
|
scrollContent: {
|
|
borderTopWidth: hairline,
|
|
borderTopColor: '#ccc',
|
|
},
|
|
});
|