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

test(map-and-label): Basic test setup #3604

Merged
merged 1 commit into from
Sep 3, 2024
Merged

Conversation

DafyddLlyr
Copy link
Contributor

@DafyddLlyr DafyddLlyr commented Aug 30, 2024

What does this PR do?

  • Sets up a basic method of testing map and label, by manually calling map.dispatchEvent()
  • One basic suite passing as an example
  • Some a11y flagged by vitest-axe fixed ✅
  • Many test.todo()s left to pick up...!

Context

It took a lot of trial and error to get here - actually simulating a user interaction with the map webcomponent is pretty tricky. Here's some of the methods tried....

The following can't access the the Shadow DOM and are either scoped to the current container or screen -

  • user.click()
  • userEvent.click()
  • fireEvent.click()

The following post proved helpful in demonstrating how to use shadow-dom-testing-library to interact with webcomponents - https://design.sis.gov.uk/get-started/test-components/testing-with-react-testing-library 🕵️‍♂️

👍 Good news - the combination of shadow-dom-testing-library and the addition of a data-testid does allow access to the map webcomponent.

👎 Bad news - even with access, the map wasn't correctly instantiated (no layers added to map, no errors I could hit). I think this may be worth digging into a little deeper as a potential solution in future.

I've settled on dispatching an event which matches the one generated by @opensystemslab/map on click. This doesn't feel like a bad solution, it's actually pretty close to a user interaction from the perspective of the codebase - we're just listening and reacting to this event.

Next steps...

  • There's an initial set of test.todos() that should be picked up - they cover some of the functionality already merged and it would be great to catch up here. This might be a good candidate for @RODO94 to pick up!
  • Once feat(map-and-label): Remove features #3595 is progressed and merged, we could update the signature of addFeaturesToMap() to incorporate the types introduced there -
export const addFeaturesToMap = async (
  map: HTMLElement,
  features: Feature<Point | Polygon, { label: string }>[],
) => {
- const mockEvent = new CustomEvent("geojsonChange", {
+ const mockEvent = new CustomEvent<GeoJSONChange>("geojsonChange", {
    detail: {
      "EPSG:3857": { features },
    },
  });
  act(() => map.dispatchEvent(mockEvent));
};

One small gotcha is that to watch out for is that all features are passed to the map component on change - this means as we test we'll need to call -

addFeaturesToMap(map, [{..}]);
addFeaturesToMap(map, [{..}, {..}]);
addFeaturesToMap(map, [{..}, {..}, {..}]);
addFeaturesToMap(map, [{..}, {..}, {..}, {..}]);

It's probably making a simple class to handle this and make it both a little safer and nice to work with. I think I'd try to spend a bit more time pursuing the shadow-dom-testing-library approach first before investing too much effort in this a and adding complexity here though. Something like...

class MockMap {
  map: HTMLElement;
  features: Feature[];

  constructor(map: HTMLElement) {
    this.map = map;
  }

  addFeature(newFeature: Feature<Point | Polygon, { label: string }>): void {
    this.features.push(newFeature);

    const mockEvent = new CustomEvent("geojsonChange", {
      detail: {
        "EPSG:3857": { features: this.features },
      },
    });
    act(() => this.map.dispatchEvent(mockEvent));
  }
}

const mockMap = new MockMap(mapEl);
mockMap.addFeature({..});
mockMap.addFeature({..});
mockMap.addFeature({..});

Comment on lines +14 to +16
if (!window.customElements.get("my-map")) {
window.customElements.define("my-map", MyMap);
}
Copy link
Contributor Author

@DafyddLlyr DafyddLlyr Aug 30, 2024

Choose a reason for hiding this comment

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

As opposed to calling this in multiple place (React app, Storybook, test suites), I think it's probably a better idea to make a basic React wrapper for the map webcomponent (<my-map/>) which includes this in a useEffect() or similar.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jessicamcinchak @jamdelion Is this part of the test defining the <my-map> component as "my-map" within the ShadowDOM to make it retrievable?

Copy link
Member

Choose a reason for hiding this comment

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

As I understand it - this checks if our custom element is already available/found in the window, and adds it if not ! As a custom web component, it naturally has a shadow DOM representation - we don't need to specifically add it to the shadow DOM, just access it from there inherently

Copy link

github-actions bot commented Aug 30, 2024

Removed vultr server and associated DNS entries

@DafyddLlyr DafyddLlyr requested a review from a team August 30, 2024 20:55
@DafyddLlyr DafyddLlyr marked this pull request as ready for review August 30, 2024 20:59
Copy link
Contributor

@RODO94 RODO94 left a comment

Choose a reason for hiding this comment

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

Looks good to me, I was thinking of merging this and running through the .todos() in a separate branch. Would this make sense @jamdelion @jessicamcinchak ?

Comment on lines +14 to +16
if (!window.customElements.get("my-map")) {
window.customElements.define("my-map", MyMap);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@jessicamcinchak @jamdelion Is this part of the test defining the <my-map> component as "my-map" within the ShadowDOM to make it retrievable?

@jessicamcinchak
Copy link
Member

Agree merging this & picking up todo()s on a separate branch is best approach here !

@jessicamcinchak jessicamcinchak merged commit 6ae1d93 into main Sep 3, 2024
12 checks passed
@jessicamcinchak jessicamcinchak deleted the dp/mal-test-todos branch September 3, 2024 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants