Skip to content
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 #20927: Error message about unsaved changes #21331

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

ujjwalpathaak
Copy link
Contributor

@ujjwalpathaak ujjwalpathaak commented Nov 23, 2024

Overview

  1. Fixes: [BUG]: Not clear how to get around the error message about unsaved changes  #20927.
  2. This PR does the following: Converts the use of a normal function to an arrow function.
  3. The original bug occurred because: When using a normal function in the destructor, the lexical scope is not preserved as a closure. However, an arrow function correctly forms a closure, retaining the lexical scope and updating the localStorage properly.

Essential Checklist

Please follow the instructions for making a code change.

  • I have linked the issue that this PR fixes in the "Development" section of the sidebar.
  • I have checked the "Files Changed" tab and confirmed that the changes are what I want to make.
  • I have written tests for my code.
  • The PR title starts with "Fix #bugnum: " or "Fix part of #bugnum: ...", followed by a short, clear summary of the changes.
  • I have assigned the correct reviewers to this PR (or will leave a comment with the phrase "@{{reviewer_username}} PTAL" if I can't assign them directly).

Proof that changes are correct

Screen.Recording.2024-11-06.at.9.59.47.AM.webm

@ujjwalpathaak ujjwalpathaak requested a review from a team as a code owner November 23, 2024 17:40
@ujjwalpathaak ujjwalpathaak requested a review from Nik-09 November 23, 2024 17:40
Copy link

oppiabot bot commented Nov 23, 2024

Assigning @Nik-09 for the first pass review of this PR. Thanks!

Copy link
Member

@Nik-09 Nik-09 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ujjwalpathaak LGTM

@Nik-09 Nik-09 assigned ujjwalpathaak and unassigned Nik-09 Nov 30, 2024
@oppiabot oppiabot bot added the PR: LGTM label Nov 30, 2024
Copy link

oppiabot bot commented Nov 30, 2024

Hi @ujjwalpathaak, this PR is ready to be merged. Please address any remaining comments prior to merging, and feel free to ask someone to merge your PR once the CI checks pass and you're happy with it. Thanks!

Copy link
Member

@HardikGoyal2003 HardikGoyal2003 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ujjwalpathaak Please also write the tests for the changes made. Thanks!

Copy link

oppiabot bot commented Dec 8, 2024

Hi @ujjwalpathaak, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 4 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 4 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you!

@oppiabot oppiabot bot added stale and removed stale labels Dec 8, 2024
@ujjwalpathaak
Copy link
Contributor Author

ujjwalpathaak commented Dec 12, 2024

@seanlip @HardikGoyal2003 I was trying to mimic the behaviour of closing the tab by window.dispatchEvent(new Event('beforeunload')); and trying to spy on onClosingStoryEditorBrowserTab function to check for the desired behaviour.

In the file core/templates/pages/story-editor-page/story-editor-page.component.spec.ts like

  it(
    'should decrement number of opened story editor tabs when ' +
      'a tab is closed',
    fakeAsync(() => {
      spyOn(undoRedoService, 'getChangeCount').and.returnValue(1);
      spyOn(urlService, 'getStoryIdFromUrl').and.returnValue('story_1');
      spyOn(pageTitleService, 'setDocumentTitle');
      component.ngOnInit();

      const onClosingStoryEditorBrowserTabSpy = spyOn(
        component,
        'onClosingStoryEditorBrowserTab'
      ).and.callThrough();

      // Opening of the first tab.
      storyEditorStateService.onStoryInitialized.emit();
      // Opening of the second tab.
      storyEditorStateService.onStoryInitialized.emit();

      let storyEditorBrowserTabsInfo: EntityEditorBrowserTabsInfo =
        localStorageService.getEntityEditorBrowserTabsInfo(
          EntityEditorBrowserTabsInfoDomainConstants.OPENED_STORY_EDITOR_BROWSER_TABS,
          story.getId()
        );

      // Making some unsaved changes on the editor page.
      storyEditorBrowserTabsInfo.setSomeTabHasUnsavedChanges(true);
      localStorageService.updateEntityEditorBrowserTabsInfo(
        storyEditorBrowserTabsInfo,
        EntityEditorBrowserTabsInfoDomainConstants.OPENED_STORY_EDITOR_BROWSER_TABS
      );

      expect(
        storyEditorBrowserTabsInfo.doesSomeTabHaveUnsavedChanges()
      ).toBeTrue();
      expect(storyEditorBrowserTabsInfo.getNumberOfOpenedTabs()).toEqual(2);

      const storyId = story.getId();

      window.dispatchEvent(new Event('beforeunload'));

      tick(200);

      expect(onClosingStoryEditorBrowserTabSpy).toHaveBeenCalled();

      storyEditorBrowserTabsInfo =
        localStorageService.getEntityEditorBrowserTabsInfo(
          EntityEditorBrowserTabsInfoDomainConstants.OPENED_STORY_EDITOR_BROWSER_TABS,
          storyId
        );

      expect(storyEditorBrowserTabsInfo.getNumberOfOpenedTabs()).toEqual(1);

      // Since the tab containing unsaved changes is closed, the value of
      // unsaved changes status will become false.
      expect(
        storyEditorBrowserTabsInfo.doesSomeTabHaveUnsavedChanges()
      ).toBeFalse();
    })
  );

tried it both with fakeAsync and without fakeAsync.
Without fakeAsync - it gave false value for expect(onClosingStoryEditorBrowserTabSpy).toHaveBeenCalled(); and expect(storyEditorBrowserTabsInfo.getNumberOfOpenedTabs()).toEqual(1);

With fakeAsync -

	Error: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'id')
	TypeError: Cannot read properties of undefined (reading 'id')
	    at Story.createFromBackendDict (core/templates/combined-tests.spec.js:66865:27851)
	    at StoryEditorStateService._updateStory (core/templates/combined-tests.spec.js:218814:52575)

i had mirrored the implementation of core/templates/pages/skill-editor-page/skill-editor-page.component.ts this is for the function onClosingSkillEditorBrowserTab... & specs for this file is not explicitly checking for the tab window close behaviour but rather the working of the function itself.

If it's been working fine is there a need to add the behaviour test for onClosingStoryEditorBrowserTab or we can skip it? as manual testing shows it's getting called on closing then tab. (shown in the demo video in PR's desc)

If it's needed to be added on both onClosingStoryEditorBrowserTabSpy & onClosingSkillEditorBrowserTab can you guide me how can i mimic the closing tab behaviour?

@seanlip
Copy link
Member

seanlip commented Dec 13, 2024

Hi @ujjwalpathaak, I'm sorry but I don't understand what you are asking. I can answer the parts I can understand:

  • Yes, you need tests that cover your changes.
  • I agree that you want to simulate that a beforeunload call does result in the effects that you want to see. Trigger that explicitly in your tests.
  • You shouldn't be mirroring (duplicating?) the implementation of a non-test file in a test.
  • There is some uncertainty about whether to use fakeAsync or not. I'm not sure what the answer is, you would need to debug that. Try and read the docs for fakeAsync to figure out whether it is relevant to your use case. If you run into errors then you would need to debug them, perhaps through logging and trying to figure out why there is a discrepancy. Another approach is to try and see what others have done (through searching on the Internet) to mimic a tab closure -- I'm not sure offhand how to do this and it will need research.

If you still run into issues I would encourage you to create a debugging doc (see our wiki) and we can guide you if you have open questions.

@ujjwalpathaak
Copy link
Contributor Author

Sorry @seanlip, if my previous message was not that clear! I'll try to explain the issue with best efforts.

  1. onClosingStoryEditorBrowserTab - the function that needs to be tested on beforeunload event
  2. oppia/core/templates/pages/story-editor-page/story-editor-page.component.spec.ts path for the function's test file.

The issue is that it's a unit test so it's not able to mimic the window reload behavious. this sums it up correctly <- read this.

fakeAsync was not correct (from my prev msg) ignore that.

I have tried many things ~ trying to dispatch the beforeunload event and test the working of onClosingStoryEditorBrowserTab but nothing seems to work.

As per my research online - in the unit test we should test the working of the onClosingStoryEditorBrowserTab which already has a test which does that - Line: 576 - story-editor-page.component.spec.ts.

Now we just need to test westher the beforeunload event is calling the onClosingStoryEditorBrowserTab function or not. this is my actual fix - to call the function on beforeunload

Now in my last message I was referring to the onClosingSkillEditorBrowserTab function's implementation it gets triggered and works exactly like the onClosingStoryEditorBrowserTab function does on beforeunload.

This only has a test which checks for the implementation of the function (Line: 528 - skill-editor-page.component.spec.ts).
No tests are there to check if onClosingSkillEditorBrowserTab is getting called on the beforeunload event ot not.

What do I think? - If we need to add the test which checks if these function are getting called on the beforeunload event or not, We will need to write E2E test as to mimic human behaviour and cause tab close.

@ujjwalpathaak
Copy link
Contributor Author

ujjwalpathaak commented Dec 16, 2024

There is where the 2nd problems comes - I cant write or debug the E2E tests on my machine.

As you know Oppia's frontend tests face problems when on macos -

  1. [BUG]: Slow Execution of Frontend Tests on Mac M1 #19894
  2. e2e tests not running on Macbook M2 ( 8gb ram ) #21190

The units tests are still manageable! but E2E tests don't work at all.

I once had a word with @Akhilesh-max too.. he also suggested that E2E tests dont run on MacOS.

What I can do is maybe raise a PR to write the E2E tests for this fix, so that someone with a linux/windows machine could write them.

Do you have any suggestion as to how can we fix the tests for Macos - It can be a really huge blocker for someone who wants to contribute and is on mac.

@seanlip
Copy link
Member

seanlip commented Dec 16, 2024

Thanks @ujjwalpathaak. I would probably try to dispatch the event. You say an approach like this does not work? Do you have a debugging doc that digs into what happens then and why it doesn't work?

Re e2e tests ... that is a separate issue, let's not combine it with this one. I think the only thing we can do is to figure out what's blocking the e2e tests on Mac and try to fix that. Do you want to give it a try? Though that would be a separate task IMO.

@ujjwalpathaak
Copy link
Contributor Author

Let me know if you are able to dispatch the event and write a test for this behaviour!

What i wanted to say was that if the unit tests are not able to test the desired behaviour of triggering a function on tab close correctly we can maybe open a new issue to write e2e tests for this behaviour instead of the unit tests.. so that someone else can pick it up.

I have a pending PR to open will try to look for a solution to the e2e tests on mac problem after it.

@seanlip
Copy link
Member

seanlip commented Dec 24, 2024

@ujjwalpathaak My previous comment still applies.

Copy link

oppiabot bot commented Dec 31, 2024

Hi @ujjwalpathaak, I'm going to mark this PR as stale because it hasn't had any updates for 7 days. If no further activity occurs within 4 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 4 days (and submit it for review, if applicable). Please also let us know if you are stuck so we can help you!

@oppiabot oppiabot bot added the stale label Dec 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants