Resetting navigation state after a deep link - react-navigation

After the app receives a deep link and navigates to it, the route (screen) that was specified as a deep link becomes the home screen! After receiving the deep link, each time the app is updated (and automatically re-loaded on the Android emulator), the app navigates to that deep link route (screen). How can I remove this route from the navigation state?
Demonstration of the Scenario:
adb shell am start -W -a android.intent.action.VIEW -d "casualjob://InvitedEmployee" com.casualjob
App is triggered by the command above and navigates to the route InvitedEmployee
User clicks on the Home screen link and navigates to it
I update the app's code
The app is automatically re-loaded to reflect the new code change
The app starts in InvitedEmployee, rather than the Home screen. I expect it to navigate to the Home screen!?
Deep Linking Configuration:
const config = {
screens: {
SingleStack: {
initialRouteName: "InitialScreen",
screens: {
EmployerActionVacancyScreen: "EmployerVacancyAction/:itemID/:opType/:itemStatus?",
ListShiftEmployeeInviteScreen: "InvitedEmployee",
InitialScreen: "*",
},
},
}
};
Stack Definition:
const SingleStack = () => {
const MyStack = createNativeStackNavigator();
return (
<MyStack.Navigator screenOptions={defaultScreenOptions}>
<MyStack.Screen name="InitialScreen" component={InitialScreen} options={{ title: "Home" }}/>
<MyStack.Screen name="ListShiftEmployeeInviteScreen" component={ListShiftEmployeeInviteScreen} options={{ title: "Shifts List", }}/>
</MyStack.Navigator>
);
};
I tried executing different pieces of code that I added to a useEffect hook in the route (screen) that the deep link leads to (InvitedEmployee in the example above). None of them seems to work!?
Solution 1 - throws an error:
The action 'RESET' with payload {"index":0,"routes":[{"name":"initialScreen"}]} was not handled by any navigator. This is a development-only warning and won't be shown in production.
const isFocused = useIsFocused();
useEffect( () => {
async function _fetchData() {
props.navigation.reset({
index: 0,
routes: [{ name: "initialScreen" }], // this is the home screen
});
}
if (isFocused) {
_fetchData();
}
}, [isFocused, ]);
solution 2: this does NOT seem to have any effect. As soon as the App is re-laoded after the code update, the deep-link's route appears back in the navigation state.
const isFocused = useIsFocused();
useEffect( () => {
async function _fetchData() {
props.navigation.dispatch(state => {
if (!state?.routes || state?.routes < 2) {
return;
}
const routes = state.routes.filter( (item, index) => {
if (item.name === "ListShiftEmployeeInviteScreen") { // This is the route (screen) that the deep link leads to
return false;
}
return true;
});
if (routes?.length > 0) {
return CommonActions.reset({
...state,
routes,
index: routes.length - 1,
});
}
return;
});
}
if (isFocused) {
_fetchData();
}
}, [isFocused, ]);

Related

Cypress.io page objects cause 'cy.click() failed because it requires a DOM element.' error

New to cypress, but did a couple projects in Protractor and TestCafe.
I'm aware of the controversy using PO's in cypress, but due to the complexity / nature of our app, we're going with it.
Refactoring the test to remove PO's and include the app ID's works. With the page objects, we get the 'requires a DOM element' error.
// myPo.js
class LoginPage {
loginPageCon() {
return cy.get('#page-login');
}
forgotPasswordLnk() {
return cy.get('#forgotPassword');
}
emailTxt() {
return cy.get('#email');
}
forgotPasswordCon() {
return cy.get('#page-forgot-password');
}
}
export default LoginPage;
// myTest.spec.js
import loginPage from '../pageObjects/myPo.js';
const loginPage = new LoginPage();
describe('Authorization', () => {
it('can direct to the azure instance', () => {
cy.visitHome();
cy.get(loginPage.loginPageCon);
});
describe('Forgot Password', () => {
it('clicking forgot password sends you to the correct screen', () => {
cy.get(loginPage.forgotPasswordLnk).click();
cy.get(loginPage.forgotPasswordCon);
});
});
});
You are returning a function reference to cy.get() when you call cy.get(loginPage.forgotPasswordLink).
Change It to:
loginPage.forgotPasswordLink().click()
Your page object is already returning a chainable of cy.get()

Vuetify: update URL when tab in v-tab is clicked

I want to be able to update the URL when a user clicks on a tab defined in v-tab. That way, the url can be shared. When another user uses that shared url, they should be able to start with the same tab that's defined in the URL. Is this possible?
You can just attach a method to the #click event of the tab element, which will change the route on click.
If you want to automatically change the selected tab when the page is loaded, you can get the current route and simply set the tab in mounted() hook:
<v-tabs
v-model="selectedTab"
>
<v-tab
v-for="tab in tabs"
#click="updateRoute(tab.route)
>
...
data () {
return {
selectedTab: 0,
tabs: [
{
name: 'tab1',
route: 'route1'
},
{
name: 'tab1',
route: 'route1'
}
]
}
},
mounted() {
// Get current route name
// Find the tab with the same route (property value)
// Set that tab as 'selectedTab'
const tabIndex = this.tabs.findIndex(tab => tab.route === this.$route.name)
this.selectedTab = tabIndex
},
methods: {
updateRoute (route) {
this.$router.push({ path: route })
}
}

Reset react navigation stack history

Update
Changed to use DrawerNavigator as the root for now, but would still like to know if it's possible to use StackNavigator as root but behavior like tabs, or drawers.
Am using reactnavigation v5.
I have the following setup:
<RootStack.Navigator initialRouteName={'SplashNavigator'}>
<RootStack.Screen name={'SplashNavigator'} component={SplashStackNavigator} options={{headerShown: false}} />
<RootStack.Screen name={'DrawerNavigator'} component={DrawerNavigator} />
</RootStack.Navigator>
From SplashNavigator I do a navigation.navigate('DrawerNavigator', {screen:'Home'})
However, the header has a back button that navigates back to the splash screen.
Is there a way to reset the history so it'll take the DrawerNavigator as the main navigator?
Have tried StackActions.replace in HomeScreen but somehow it doesn't recognise the screen.
const HomeScreen = ({navigation}) => {
useEffect(() => {
navigation.dispatch(state => {
console.log(state);
return StackActions.replace('Home')
});
}, []);
...
ExceptionsManager.js:173 The action 'REPLACE' with payload {"name":"Home"} was not handled by any navigator.
Yet I do see the route in the state
"routeNames": [
"Home",
"Promotions"
],
Have tried CommonActions.reset() too but it didn't change anything.
const HomeScreen = ({navigation}) => {
useEffect(() => {
navigation.dispatch(state => {
console.log(state);
return CommonActions.reset({...state, key:null})
});

Protractor expect direct to a page with specific url

I have a button on my page, I want to write an e2e test using Protractor. What I want to implement is that when clicking the button, page change to http://localhost:8100/#/booking. How can I implement that?
describe('booking function', function() {
it('should go to booking page', function() {
broswer.get(localHostCruises);
element(by.css('.button.button-stable.button-block')).click();
//sudo code
expect(page change to "http://localhost:8100/#/book" );
})
})
you need to use the browser.getCurrentUrl() method, so something like this:
element(by.css('.button.button-stable.button-block')).click().then(function () {
expect(browser.getCurrentUrl()).toEqual("http://localhost:8100/#/book");
})
You can achieve this with below code.
let targetLocation = 'your/target/location';
browser.get('localHostCruises'); // Login page.
element(by.css('.button.button-stable.button-block')).click(); // click on button.
browser.setLocation(targetLocation);
// If Login takes some time, so wait until it's done.
browser.wait(() => {
return browser.getCurrentUrl().then((url) => {
let isMatch = url.match(targetLocation);
if (isMatch) {
page = new Page; // I assume you writing test cases in page object.
} else {
browser.setLocation(targetLocation);
}
return isMatch;
});
}, 2000, 'Should throw an error message.');

How to refresh content when using CrossroadJS and HasherJS with KnockoutJS

I was following Lazy Blogger for getting started with routing in knockoutJS using crossroads and hasher and it worked correctly.
Now I needed to refresh the content using ajax for Home and Settings page every time they are clicked. So I googled but could not find some useful resources. Only these two links
Stack Overflow Here I could not understand where to place the ignoreState property and tried these. But could not make it work.
define(["jquery", "knockout", "crossroads", "hasher"], function ($, ko, crossroads, hasher) {
return new Router({
routes:
[
{ url: '', params: { page: 'product' } },
{ url: 'log', params: { page: 'log' } }
]
});
function Router(config) {
var currentRoute = this.currentRoute = ko.observable({});
ko.utils.arrayForEach(config.routes, function (route) {
crossroads.addRoute(route.url, function (requestParams) {
currentRoute(ko.utils.extend(requestParams, route.params));
});
});
activateCrossroads();
}
function activateCrossroads() {
function parseHash(newHash, oldHash) {
//crossroads.ignoreState = true; First try
crossroads.parse(newHash);
}
crossroads.normalizeFn = crossroads.NORM_AS_OBJECT;
hasher.initialized.add(parseHash);
hasher.changed.add(parseHash);
hasher.init();
$('a').on('click', function (e) {
crossroads.ignoreState = true; //Second try
});
}
});
Crossroads Official Page Here too I could not find where this property need to be set.
If you know then please point me to some url where I can get more details about this.

Resources