Skip to content

Commit

Permalink
fix(transition): fallback to initial transition & headless in testing
Browse files Browse the repository at this point in the history
BREAKING CHANGE: headless mode will automatically be enabled in any testing environment
  • Loading branch information
tobua committed Sep 30, 2023
1 parent 070487f commit d2f0674
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 40 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@ go('First', SuperSlow)
back(SuperFastOpacity)
```

## Headless Mode for Testing

Headless mode will automatically be enabled in a testing environment `process.env.NODE === 'test'`. It's also possible to control this mode manually on the main component.

```jsx
import Reactigation from 'reactigation'

const App = () => <Reactigation headless={false} />
AppRegistry.registerComponent('NavigationApp', () => App)
```

## Running the Example App

The example app shown on top is found in the repository. Run it by cloning this repository and then executing the following commands inside the main directory.
Expand Down
10 changes: 5 additions & 5 deletions animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const handlerLeft =
value: Animated.Value,
done: () => void,
{ duration }: { duration: number },
reverse?: boolean
reverse?: boolean,
) =>
() => {
Animated.timing(value, {
Expand Down Expand Up @@ -48,7 +48,7 @@ const handlerOpacity =
value: Animated.Value,
done: () => void,
{ duration }: { duration: number },
reverse?: boolean
reverse?: boolean,
) =>
() => {
Animated.timing(value, {
Expand All @@ -73,7 +73,7 @@ const opacity = (duration = 500) => ({
done()
},
{ duration },
reverse
reverse,
)
},
})
Expand All @@ -83,7 +83,7 @@ const handlerTop =
value: Animated.Value,
done: () => void,
{ duration }: { duration: number },
reverse?: boolean
reverse?: boolean,
) =>
() => {
Animated.timing(value, {
Expand All @@ -109,7 +109,7 @@ const handlerTopHalf =
value: Animated.Value,
done: () => void,
{ height, duration }: { height: number; duration: number },
reverse?: boolean
reverse?: boolean,
) =>
() => {
Animated.timing(value, {
Expand Down
2 changes: 1 addition & 1 deletion app/component/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const Modal = ({ title }) => (
<Text style={styles.title}>{title}</Text>
{title !== 'PeekModal' && (
<>
<TouchableOpacity onPress={() => go('PeekModal', 'peek')}>
<TouchableOpacity onPress={() => go('PeekModal')}>
<Text style={styles.description}>Peek Another Modal</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => go('PeekModal', AlmostFullPeek)}>
Expand Down
18 changes: 9 additions & 9 deletions index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,17 @@ export const initial = (name: string) => {
}

// Go to certain screen.
export const go = (
name: string,
transition: TransitionInput = Transition.regular,
props?: object,
) => {
export const go = (name: string, transition?: TransitionInput, props?: object) => {
if (isTransitioning()) {
return console.warn('Reactigation: Transition already in progress.')
}
const currentScreen = screens[name]
if (!currentScreen) {
return console.warn(`Reactigation: Screen ${name} wasn't registered.`)
}
if (!transition) {
transition = currentScreen.transition ?? Transition.regular
}
if (!isTransitionValid(transition, 'go')) {
return
}
Expand Down Expand Up @@ -155,7 +154,7 @@ BackHandler.addEventListener('hardwareBackPress', () => {
return true
})

const renderBottom = ({ Bottom }: { Bottom: Screen | null }) => {
const renderBottom = ({ Bottom }: State) => {
if (!Bottom) {
return
}
Expand All @@ -176,9 +175,9 @@ const renderBottom = ({ Bottom }: { Bottom: Screen | null }) => {
)
}

const renderTop = ({ Top, reverse, left, top, opacity, backdrop }: State) => {
const renderTop = ({ Top, Bottom, reverse, left, top, opacity, backdrop }: State) => {
const TopWithProps = cloneElement(Top.Component, {
backPossible: history.length > 1 || !!reverse,
backPossible: history.length > 1 || (!!reverse && Bottom === history[0]),
title: Top.name,
...Top.props,
})
Expand Down Expand Up @@ -206,7 +205,8 @@ const renderTop = ({ Top, reverse, left, top, opacity, backdrop }: State) => {
return screen
}

export default ({ headless = false }) => {
// Disable transitions and render only top screen, useful for programmatic tests.
export default ({ headless = process.env.NODE_ENV === 'test' }) => {
const [state, setState] = useState<State>(initialPosition(history[0]))
const afterRender = connect({ setState, state }, headless)

Expand Down
18 changes: 9 additions & 9 deletions test/basic.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ test('Renders a single registered screen.', () => {
const names = ['FirstScreen']
const input = setupScreens(names)

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand All @@ -40,7 +40,7 @@ test('Can render several screens.', () => {
const names = ['FirstScreen', 'SecondScreen', 'ThirdScreen']
const input = setupScreens(names)

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand All @@ -58,7 +58,7 @@ test('Can navigate between screens.', () => {
const names = ['FirstScreen', 'SecondScreen', 'ThirdScreen']
const input = setupScreens(names)

render(<Navigation />)
render(<Navigation headless={false} />)

expect(input[0].mock.calls.length).toEqual(1)
expect(input[0].effectMock.calls.length).toEqual(1)
Expand Down Expand Up @@ -88,7 +88,7 @@ test("Back isn't possible for last screen.", () => {
const names = ['FirstScreen', 'SecondScreen', 'ThirdScreen']
const input = setupScreens(names)

render(<Navigation />)
render(<Navigation headless={false} />)

// Visible screens have been rendered, back initially not possible.
expect(input[0].mock.calls.length).toEqual(1)
Expand Down Expand Up @@ -144,7 +144,7 @@ test('Props can be passed to screen with go().', () => {
const names = ['FirstScreen', 'SecondScreen', 'ThirdScreen']
const input = setupScreens(names)

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand Down Expand Up @@ -205,7 +205,7 @@ test('Warning if unknown transition is used.', () => {
const names = ['FirstScreen']
const input = setupScreens(names)

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand Down Expand Up @@ -239,7 +239,7 @@ test('Can use enum or string as transition.', () => {
const names = ['FirstScreen']
const input = setupScreens(names)

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand Down Expand Up @@ -309,7 +309,7 @@ test('Initially shown screen can be configured.', () => {

initial('SecondScreen')

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand All @@ -331,7 +331,7 @@ test('Initially shown screen can be configured though register.', () => {
]
const input = setupScreens(names)

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand Down
2 changes: 1 addition & 1 deletion test/docs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ test('Two Screen Example with Interaction.', () => {
register(<FirstScreen />, 'First')
register(<SecondScreen />, 'Second')

const { screens } = render(<Navigation />)
const { screens } = render(<Navigation headless={false} />)

expect(screens.length).toEqual(1)

Expand Down
16 changes: 8 additions & 8 deletions test/hook.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ test('Hook is called with initial screen.', () => {

const { tree, wrappers } = render(
<>
<Navigation />
<Navigation headless={false} />
<Hook currentScreenMock={hookMock} />
</>
</>,
)

expect(wrappers.length).toEqual(1)
Expand All @@ -43,9 +43,9 @@ test('Hook is called with first registered screen.', () => {

render(
<>
<Navigation />
<Navigation headless={false} />
<Hook currentScreenMock={hookMock} />
</>
</>,
)

expect(hookMock.mock.calls[0][0]).toEqual('SecondScreen')
Expand All @@ -60,9 +60,9 @@ test('Hook is updated when screen changes.', () => {

render(
<>
<Navigation />
<Navigation headless={false} />
<Hook currentScreenMock={hookMock} />
</>
</>,
)

expect(hookMock.mock.calls[0][0]).toEqual(names[0])
Expand Down Expand Up @@ -99,10 +99,10 @@ test('Hook updates all listeners.', () => {

render(
<>
<Navigation />
<Navigation headless={false} />
<Hook currentScreenMock={hookMock} />
<Hook currentScreenMock={secondHookMock} />
</>
</>,
)

expect(hookMock.mock.calls[0][0]).toEqual(names[0])
Expand Down
2 changes: 1 addition & 1 deletion test/utils/setup-screens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import createTestScreen from '../components/Screen'
export default (screens: (string | { name: string; options?: { initial?: boolean } })[]) => {
return screens.map((screen) => {
let name
let options = {}
let options = {} as any

if (typeof screen === 'string') {
name = screen
Expand Down
10 changes: 6 additions & 4 deletions transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const connect = (
// Sets initial screen and values.
export const initialPosition: (Top: Screen) => State = (Top) => ({
Top,
Bottom: null,
Bottom: undefined,
left: new Animated.Value(0),
top: new Animated.Value(0),
opacity: new Animated.Value(1),
Expand All @@ -47,11 +47,12 @@ export const isTransitionValid = (transition: TransitionInput, method: string) =

export default (
Top: Screen,
Bottom: Screen,
Bottom: Screen | undefined,
animation: TransitionInput = Transition.regular,
reverse = false,
) => {
const transition = typeof animation === 'string' ? animations[animation] : animation
let transition = typeof animation === 'string' ? animations[animation] : animation

running = true
const done = () => {
running = false
Expand All @@ -71,8 +72,9 @@ export default (
state.top.setValue(0)
running = false

if (reverse) {
if (reverse && Bottom) {
Top = Bottom
Bottom = undefined
}
}

Expand Down
4 changes: 2 additions & 2 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Animated } from 'react-native'
export type AnimationHandler = (
state: State,
done: () => void,
reverse?: boolean
reverse?: boolean,
) => (() => void) | null

export type Animation = {
Expand Down Expand Up @@ -39,6 +39,6 @@ export type State = {
opacity: Animated.Value
backdrop?: boolean
Top: Screen
Bottom: Screen | null
Bottom?: Screen
reverse?: boolean
}

0 comments on commit d2f0674

Please sign in to comment.