-
-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(router): canDeactivate correctly cancels browser history navigation #621
base: master
Are you sure you want to change the base?
Conversation
Preventing a navigation with canDeactivate doesn't cancel the browser history navigation. This fix moves the browser back to the index where navigation was cancelled. Depending on PR aurelia/history-browser#42. Closes aurelia#528.
Due to the lack of tests performed (pushstate, other browsers than Chrome, etc) this is a somewhat preliminary PR. |
src/app-router.js
Outdated
router.navigate(router.history.previousLocation, { trigger: false, replace: true }); | ||
Promise.resolve().then(() => { | ||
if (router.lastHistoryMovement && !isNaN(router.lastHistoryMovement)) { | ||
router.history.history.go(-router.lastHistoryMovement); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this read "assume the History
implementation from Aurelia always have a history pointing to underlying platform History
"? @jwx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Err, yeah, unfortunately. It should be rewritten so that it only goes to the History
implementation (which already requires navigateBack
so go
or move
should be acceptable there). Once @davismj has taken a look at this "preliminary" PR and approved of my solution to the problem, I'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I like your PRs to enhance the aurelia's History
implementation. Looking towards it.
Overall, I think this is great and a workable strategy. Wish I had thought of using the history state API. Nice work @jwx. As @bigopon mentioned, let's go ahead and implement an abstraction of history.go on the history and history-browser modules and use that instead. There's one remaining edge case bug that I'm not sure we're going to solve here. Let's say your history looks like this: One <== current If you use One Assume canDeactivate in One should have failed. When the user navigates back, the developer might expect the user to end up at Two, however the user ends up at Three. I believe this bug is out of the scope of the original bug report and I'd be fine letting it ride for now. It won't break anyone's application. |
@davismj Yeah, I've noticed that edge case as well. I agree with you on scope and would rather say that the edge case is due to a navigation bug where (some of) the life cycle isn't invoked. I'll implement the history abstractions and make the router changes later today or tomorrow. |
Seems you added some extra vscode and karma edits by accident that need to be removed. Core code is perfect. Good work. I'm not sold on the tests, and I really want to make sure the tests are solid because we've definitely burned a few Aurelia developers in the past on issues that could have been solved through better testing. I've pinged @fkleuver for his expert opinion. |
Nice work! I like the mock, it helps verify the low-level interactions of these changes. I would personally add a small loop (or a few copy-pastes) to verify different numeric values for just that extra bit of confidence. I'm only spotting -1. In addition to the mock, it's probably also a good idea to have an integration test with the actual BrowserHistory implementation and verify the final outcome as well. I made the horrible mistake of installing node 10 on my windows box and of course this gulp project breaks. I can't verify the test coverage. Did you check that all the changes have coverage? |
@@ -0,0 +1,30 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be here.
@@ -71,9 +71,14 @@ module.exports = function(config) { | |||
|
|||
// start these browsers | |||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher | |||
browsers: ['Chrome'], | |||
|
|||
browsers: ['ChromeDebugging'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? This allows you to attach vs code to chrome and debug from within vs code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not saying it's not a good change, I'm just saying its out of the scope of this particular PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm I guess I can't really argue with that.. I must admit we've gotten a bit lax with scope creep on the vNext repo for the sake of progressing faster, but probably good to keep it a bit more strict here
@@ -5,13 +5,48 @@ import {RouteLoader} from '../src/route-loading'; | |||
import {Pipeline} from '../src/pipeline'; | |||
|
|||
class MockHistory extends History { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sold on this implementation for tests. In my experience, when you build a mock object that does more than noops, it opens the door wide open for bad integration tests, when the mock doesn't match the class you're mocking. I'd love to have @fkleuver weigh in on this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A mock isn't necessarily meant to be used for integration tests in the first place. In an integration test you use real implementations. A mock allows you to unit test a specific piece of behavior by making the mock return some pre-configured values and to verify that the SUT calls the component in the correct manner.
Here's an example of a pass-through expression (that technically speaking is a spy, not a mock) that I use to fully verify the interactions. It's used by integration tests: https://github.com/aurelia/aurelia/blob/master/packages/runtime/test/unit/mock.ts#L853
Here's an example of something that's more like a mock, where I short circuit about 5 different components by passing some hard-coded values in the constructor, and it still mostly mimics the real behavior: https://github.com/aurelia/aurelia/blob/master/packages/runtime/test/unit/mock.ts#L377
Neither of these by themselves would ever be sufficient for testing a particular piece, but they are useful for isolating things on a more granular level. There still need to be full integration tests in addition.
So if this mock serves the purpose of granular verification, that's fine, just by itself it isn't enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking in this case we want to mock the browser's history object, but want to use the actual implementation of history-browser for the tests. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in any other case I'd say preferably both. But it might not be possible to use the actual browser's history object without, well, navigating away from the testing page and crashing the tests :) I haven't tried that before, I wonder if it's possible
@jwx Any progress on the tests? |
Yeah, one test left to go. Unfortunately, it's a bit of a struggle. Hopefully I'll be able to sort it out tonight or tomorrow. |
@jwx I've started working on fixing the tests. Please see my commits here: https://github.com/davismj/router/tree/fix/can-deactivate-history. You're going to want to rebase onto this, or create a new branch and pull all these commits, as I've rebased on the TypeScript refactor for you. After struggling with the first test, which restores the previous location on not-found, I found the issue wasn't the tests but the feature. |
@jwx have you had any time to look at this and get it fixed? |
Hi guys! I'm coming back to check how this fix is going... I see all tests have passed, can't we just fix the conflicts and merge this so we could have it in next month release? |
@davismj Can you comment on this? |
@gama410 So the history here is I tried to fix it and couldn't. @jwx tried to fix it and made better progress but there were still issues. I tried to fix the issues but again couldn't (see #621 (comment)). There has been no activity since then. @bigopon has expressed an interest in fixing it. This is a non-trivial bug that will take a significant effort to repair. I've already spent days looking into it with little success. I apologize for the inconvenience it has caused, but please understand that we are not simply ignoring you. |
@davismj I understand totally, don't worry. I'm glad to have some feedback. I hope you'll get to a working solution! |
Hi everyone, This PR has been stalled for quite some time now. Due to the same bug in our production app, our team is becoming interested in this fix. |
Thanks @avrahamcool . One of the reasons why this wasn't moved quickly was because it wasn't sufficiently tested. We need better testing setup, with probably real browser history and interaction. We can use either cypress/playwright for this. I'll gladly support any PR as long as we have that test setup. I can also help set it up if necessary. |
Hi @bigopon, |
Preventing a navigation with canDeactivate doesn't cancel the browser history navigation. This fix moves the browser back to the index where navigation was cancelled.
Depending on PR aurelia/history-browser#42.
Closes #528.