alessandro trinca tornidor commited on
Commit
7edcc96
·
1 Parent(s): 52cfa0b

test: add data-test-id and aria-labels to improve the playwright tests

Browse files
static/e2e/{samgis-be.spec.ts → samgis-be-driverjs.spec.ts} RENAMED
@@ -37,12 +37,19 @@ test('test the driver.js tour on the localhost SamGIS-be page', async ({ page })
37
  await expect(navigationMapLock).toBeVisible()
38
  await expect(navigationMapLock).not.toBeChecked()
39
 
40
- const mapLocator = page.locator("#map")
41
  await expect(mapLocator).toBeVisible()
42
  await expect(mapLocator).toMatchAriaSnapshot({ name: 'mapLocatorTestDriverJS.aria.yaml'})
43
 
44
  const sendButton = page.getByRole('button', { name: 'Empty prompt (disabled)' })
45
  await expect(sendButton).toBeVisible()
46
  await expect(sendButton).toBeDisabled()
 
 
 
 
 
 
47
  await page.close();
48
  });
 
 
37
  await expect(navigationMapLock).toBeVisible()
38
  await expect(navigationMapLock).not.toBeChecked()
39
 
40
+ const mapLocator = page.getByTestId("map-container")
41
  await expect(mapLocator).toBeVisible()
42
  await expect(mapLocator).toMatchAriaSnapshot({ name: 'mapLocatorTestDriverJS.aria.yaml'})
43
 
44
  const sendButton = page.getByRole('button', { name: 'Empty prompt (disabled)' })
45
  await expect(sendButton).toBeVisible()
46
  await expect(sendButton).toBeDisabled()
47
+
48
+ const footerMsg = page.getByText('Trouble on scrolling this page? Open the direct URL space as a new tab. SamGIS')
49
+ await expect(footerMsg).toBeVisible();
50
+ await page.getByRole('button', { name: 'Close' }).click();
51
+ await expect(footerMsg).not.toBeVisible();
52
+
53
  await page.close();
54
  });
55
+
static/src/components/NavBar/MobileNavBar.vue CHANGED
@@ -1,9 +1,9 @@
1
  <template>
2
- <div class="bg-gray-200 items-center h-8">
3
  <TabComponent description="About SamGIS" href="https://trinca.tornidor.com/projects/samgis-segment-anything-applied-to-GIS" />
4
  <TabComponent description="My blog" href="https://trinca.tornidor.com/" />
5
  <TabComponent description="SamGIS docs" href="https://docs.ml-trinca.tornidor.com/" />
6
- </div>
7
  </template>
8
 
9
  <script setup lang="ts">
 
1
  <template>
2
+ <nav class="bg-gray-200 items-center h-8" data-testid="mobile-navbar" aria-label="Mobile navigation">
3
  <TabComponent description="About SamGIS" href="https://trinca.tornidor.com/projects/samgis-segment-anything-applied-to-GIS" />
4
  <TabComponent description="My blog" href="https://trinca.tornidor.com/" />
5
  <TabComponent description="SamGIS docs" href="https://docs.ml-trinca.tornidor.com/" />
6
+ </nav>
7
  </template>
8
 
9
  <script setup lang="ts">
static/src/components/NavBar/NavBar.vue CHANGED
@@ -1,9 +1,9 @@
1
  <template>
2
- <div class="fixed top-2 right-5 mr-2 items-center">
3
  <TabComponent description="About SamGIS" href="https://trinca.tornidor.com/projects/samgis-segment-anything-applied-to-GIS" />
4
  <TabComponent description="My blog" href="https://trinca.tornidor.com/" />
5
  <TabComponent description="SamGIS docs" href="https://docs.ml-trinca.tornidor.com/" />
6
- </div>
7
  </template>
8
 
9
  <script setup lang="ts">
 
1
  <template>
2
+ <nav class="fixed top-2 right-5 mr-2 items-center" data-testid="navbar" aria-label="Main navigation">
3
  <TabComponent description="About SamGIS" href="https://trinca.tornidor.com/projects/samgis-segment-anything-applied-to-GIS" />
4
  <TabComponent description="My blog" href="https://trinca.tornidor.com/" />
5
  <TabComponent description="SamGIS docs" href="https://docs.ml-trinca.tornidor.com/" />
6
+ </nav>
7
  </template>
8
 
9
  <script setup lang="ts">
static/src/components/NavBar/TabComponent.vue CHANGED
@@ -3,6 +3,8 @@
3
  <a :href="props.href"
4
  class="bg-white border-2 no-underline pl-2 pr-2 p-1
5
  landscape:border-gray-300 landscape:font-semibold landscape:text-lg"
 
 
6
  >{{ props.description }}</a>
7
  </h2>
8
  </template>
 
3
  <a :href="props.href"
4
  class="bg-white border-2 no-underline pl-2 pr-2 p-1
5
  landscape:border-gray-300 landscape:font-semibold landscape:text-lg"
6
+ :data-testid="`tab-${props.description.toLowerCase().replace(/\s+/g, '-')}`"
7
+ :aria-label="props.description"
8
  >{{ props.description }}</a>
9
  </h2>
10
  </template>
static/src/components/PageFooter.vue CHANGED
@@ -1,6 +1,6 @@
1
  <template>
2
  <!-- style 'z-index: 1001' here is needed to avoid override from leafletjs css -->
3
- <footer class="fixed bottom-0 w-full pl-4 font-light text-xs" style="z-index: 9999;" v-if="showFooterRef">
4
  <div class="relative flex items-center bg-gray-200 h-6">
5
  <div class="pl-1 w-full">
6
  <p class="">
@@ -17,6 +17,7 @@
17
  <div class="pr-2">
18
  <button
19
  aria-label="Close"
 
20
  class="shrink-0 rounded-lg bg-black/10 p-1 transition hover:bg-black/20"
21
  @click="showFooterRef = !showFooterRef"
22
  >Close</button>
 
1
  <template>
2
  <!-- style 'z-index: 1001' here is needed to avoid override from leafletjs css -->
3
+ <footer class="fixed bottom-0 w-full pl-4 font-light text-xs" style="z-index: 9999;" v-if="showFooterRef" data-testid="page-footer">
4
  <div class="relative flex items-center bg-gray-200 h-6">
5
  <div class="pl-1 w-full">
6
  <p class="">
 
17
  <div class="pr-2">
18
  <button
19
  aria-label="Close"
20
+ data-testid="footer-close-button"
21
  class="shrink-0 rounded-lg bg-black/10 p-1 transition hover:bg-black/20"
22
  @click="showFooterRef = !showFooterRef"
23
  >Close</button>
static/src/components/PageFooterHyperlink.vue CHANGED
@@ -4,6 +4,7 @@
4
  class="underline"
5
  target="_blank"
6
  rel="noopener noreferrer"
 
7
  >
8
  <slot />
9
  </a>
 
4
  class="underline"
5
  target="_blank"
6
  rel="noopener noreferrer"
7
+ :data-testid="`footer-link-${props.path.replace(/https?:\/\//, '').replace(/[^a-z0-9]+/gi, '-').replace(/-$/, '').toLowerCase()}`"
8
  >
9
  <slot />
10
  </a>
static/src/components/PageLayout.vue CHANGED
@@ -1,11 +1,11 @@
1
  <template>
2
- <div class="relative min-h-screen lg:flex">
3
  <!-- Menubar -->
4
  <NavBar class="hidden portrait:sd:hidden portrait:md:flex landscape:flex" style="z-index: 9999;"/>
5
  <MobileNavBar class="flex portrait:sd:flex portrait:md:hidden landscape:hidden" style="z-index: 9999;"/>
6
 
7
  <main id="content" class="flex-1 z-1 lg:ml-0 mr-4 overflow-y-auto md:pl-1 lg:h-screen">
8
- <header class="hidden items-center justify-between h-10 ml-2 landscape:md:flex portrait:sd:flex portrait:md:h-12 bg-gray-200 border-b">
9
  <h2 class="hidden sd:text-sm ml-2 md:block md:text-2xl">{{ props.pageTitle }}</h2>
10
  </header>
11
 
 
1
  <template>
2
+ <div class="relative min-h-screen lg:flex" data-testid="page-layout">
3
  <!-- Menubar -->
4
  <NavBar class="hidden portrait:sd:hidden portrait:md:flex landscape:flex" style="z-index: 9999;"/>
5
  <MobileNavBar class="flex portrait:sd:flex portrait:md:hidden landscape:hidden" style="z-index: 9999;"/>
6
 
7
  <main id="content" class="flex-1 z-1 lg:ml-0 mr-4 overflow-y-auto md:pl-1 lg:h-screen">
8
+ <header class="hidden items-center justify-between h-10 ml-2 landscape:md:flex portrait:sd:flex portrait:md:h-12 bg-gray-200 border-b" aria-label="Page header">
9
  <h2 class="hidden sd:text-sm ml-2 md:block md:text-2xl">{{ props.pageTitle }}</h2>
10
  </header>
11
 
static/src/components/PagePredictionMap.vue CHANGED
@@ -1,10 +1,10 @@
1
  <template>
2
- <div class="h-auto" id="id-prediction-map-container">
3
 
4
  <div class="grid grid-cols-1 2xl:grid-cols-5 lg:gap-1 lg:border-r ml-2 mt-2 md:ml-4 md:mr-4">
5
 
6
  <div class="lg:border-r lg:col-span-3">
7
- <div id="id-map-cont" class="">
8
  <p class="hidden lg:block">{{ description }}</p>
9
  <div class="w-full md:pt-1 md:pb-1">
10
  <ButtonMapSendRequest
@@ -18,19 +18,19 @@
18
  :waiting-string="waitingString"
19
  />
20
  <span class="ml-2">
21
- <input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" />
22
  <span class="ml-2">
23
  <label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map navigation!</label>
24
  <label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map navigation unlocked</label>
25
  </span>
26
  </span>
27
  </div>
28
- <div id="map" class="map-predictions" />
29
  </div>
30
  </div>
31
 
32
  <div class="lg:col-span-2">
33
- <div class="lg:pl-2 lg:pr-2 lg:border-l lg:border-3" id="id-map-info">
34
 
35
  <h1>Map Info</h1>
36
  <div class="grid grid-cols-1 md:grid-cols-3">
@@ -53,25 +53,27 @@
53
  </div>
54
  </div>
55
 
56
- <h1 id="id-ml-request-prompt">ML request prompt</h1>
57
  <p>Exclude points: label 0, include points: label 1.</p>
58
- <div v-if="promptsArrayRef.filter(el => {return el.type === 'point'}).length > 0">
59
- <TableGenericComponent
60
- :header="['id', 'data', 'label']"
61
- :rows="applyFnToObjectWithinArray(promptsArrayRef.filter(el => {return el.type === 'point'}))"
62
- title="Points"
63
- row-key="id"
64
- />
65
- </div>
66
- <br />
67
- <div v-if="promptsArrayRef.filter(el => {return el.type === 'rectangle'}).length > 0">
68
- <TableGenericComponent
69
- :header="['id', 'data_ne', 'data_sw']"
70
- :rows="applyFnToObjectWithinArray(promptsArrayRef.filter(el => {return el.type === 'rectangle'}))"
71
- title="Rectangles"
72
- row-key="id"
73
- class="2md:min-h-[100px]"
74
- />
 
 
75
  </div>
76
  </div>
77
 
 
1
  <template>
2
+ <div class="h-auto" id="id-prediction-map-container" data-testid="prediction-map-container">
3
 
4
  <div class="grid grid-cols-1 2xl:grid-cols-5 lg:gap-1 lg:border-r ml-2 mt-2 md:ml-4 md:mr-4">
5
 
6
  <div class="lg:border-r lg:col-span-3">
7
+ <div id="id-map-cont" class="" data-testid="map-section">
8
  <p class="hidden lg:block">{{ description }}</p>
9
  <div class="w-full md:pt-1 md:pb-1">
10
  <ButtonMapSendRequest
 
18
  :waiting-string="waitingString"
19
  />
20
  <span class="ml-2">
21
+ <input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" data-testid="map-navigation-checkbox" />
22
  <span class="ml-2">
23
  <label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map navigation!</label>
24
  <label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map navigation unlocked</label>
25
  </span>
26
  </span>
27
  </div>
28
+ <div id="map" class="map-predictions" data-testid="map-container" />
29
  </div>
30
  </div>
31
 
32
  <div class="lg:col-span-2">
33
+ <div class="lg:pl-2 lg:pr-2 lg:border-l lg:border-3" id="id-map-info" data-testid="map-info">
34
 
35
  <h1>Map Info</h1>
36
  <div class="grid grid-cols-1 md:grid-cols-3">
 
53
  </div>
54
  </div>
55
 
56
+ <h1 id="id-ml-request-prompt" data-testid="ml-request-prompt">ML request prompt</h1>
57
  <p>Exclude points: label 0, include points: label 1.</p>
58
+ <div aria-label="Table container for the positions of map markers and rectangles">
59
+ <div v-if="promptsArrayRef.filter(el => {return el.type === 'point'}).length > 0">
60
+ <TableGenericComponent
61
+ :header="['id', 'data', 'label']"
62
+ :rows="applyFnToObjectWithinArray(promptsArrayRef.filter(el => {return el.type === 'point'}))"
63
+ title="Table with the position for the map markers"
64
+ row-key="id"
65
+ />
66
+ </div>
67
+ <br />
68
+ <div v-if="promptsArrayRef.filter(el => {return el.type === 'rectangle'}).length > 0">
69
+ <TableGenericComponent
70
+ :header="['id', 'data_ne', 'data_sw']"
71
+ :rows="applyFnToObjectWithinArray(promptsArrayRef.filter(el => {return el.type === 'rectangle'}))"
72
+ title="Table with the position for the map rectangles"
73
+ row-key="id"
74
+ class="2md:min-h-[100px]"
75
+ />
76
+ </div>
77
  </div>
78
  </div>
79
 
static/src/components/StatsGrid.vue CHANGED
@@ -1,5 +1,5 @@
1
  <template>
2
- <dl class="grid md:pt-1 md:pb-1" v-for="item in props.statsArray" v-bind:key="item.statName">
3
  <div class="flex flex-col bg-blue-100 text-center p-1 md:p-2">
4
  <dt class="order-last font-medium">{{ item.statName }}</dt>
5
  <dd class="text-lg font-extrabold text-blue-600">{{ item.statValue }}</dd>
 
1
  <template>
2
+ <dl class="grid md:pt-1 md:pb-1" v-for="item in props.statsArray" v-bind:key="item.statName" data-testid="stats-grid">
3
  <div class="flex flex-col bg-blue-100 text-center p-1 md:p-2">
4
  <dt class="order-last font-medium">{{ item.statName }}</dt>
5
  <dd class="text-lg font-extrabold text-blue-600">{{ item.statValue }}</dd>
static/src/components/TableGenericComponent.vue CHANGED
@@ -1,5 +1,5 @@
1
  <template>
2
- <table class="min-w-full divide-y-2 divide-gray-200 border border-gray-200 bg-white text-left p-4">
3
  <caption class="text-2xl bg-blue-100">{{ props.title }}</caption>
4
  <thead class="text-left">
5
  <tr class="text-left">
 
1
  <template>
2
+ <table class="min-w-full divide-y-2 divide-gray-200 border border-gray-200 bg-white text-left p-4" data-testid="table-component" :aria-label="props.title">
3
  <caption class="text-2xl bg-blue-100">{{ props.title }}</caption>
4
  <thead class="text-left">
5
  <tr class="text-left">
static/src/components/buttons/ButtonMapSendRequest.vue CHANGED
@@ -3,12 +3,16 @@
3
  :class="`${props.class} bg-gray-200 bg-opacity-50`"
4
  :disabled="promptsArray.length === 0 || responseMessage === waitingString"
5
  v-if="promptsArray.length === 0 || responseMessage === waitingString"
 
 
6
  >{{ responseMessage === waitingString ? responseMessage : '🚫 Empty prompt (disabled)' }}
7
  </button>
8
  <button
9
  :class="`${props.class} bg-blue-300 whitespace-no-wrap overflow-hidden truncate`"
10
  @click="sendMLRequest(map, promptsArray, currentBaseMapName)"
11
  v-else
 
 
12
  >
13
  <span v-if="responseMessage && responseMessage !== '-'">{{ responseMessage }}</span>
14
  <span v-else>🔍 send ML request</span>
 
3
  :class="`${props.class} bg-gray-200 bg-opacity-50`"
4
  :disabled="promptsArray.length === 0 || responseMessage === waitingString"
5
  v-if="promptsArray.length === 0 || responseMessage === waitingString"
6
+ data-testid="submit-button-disabled"
7
+ aria-disabled="true"
8
  >{{ responseMessage === waitingString ? responseMessage : '🚫 Empty prompt (disabled)' }}
9
  </button>
10
  <button
11
  :class="`${props.class} bg-blue-300 whitespace-no-wrap overflow-hidden truncate`"
12
  @click="sendMLRequest(map, promptsArray, currentBaseMapName)"
13
  v-else
14
+ data-testid="submit-button"
15
+ aria-label="Send ML request"
16
  >
17
  <span v-if="responseMessage && responseMessage !== '-'">{{ responseMessage }}</span>
18
  <span v-else>🔍 send ML request</span>
static/tests/MobileNavBar.test.ts CHANGED
@@ -3,9 +3,12 @@ import { shallowMount } from '@vue/test-utils'
3
  import MobileNavBar from '@/components/NavBar/MobileNavBar.vue'
4
 
5
  describe('MobileNavBar', () => {
6
- it('renders a container div with bg-gray-200 class', () => {
7
  const wrapper = shallowMount(MobileNavBar)
8
- expect(wrapper.find('div.bg-gray-200').exists()).toBe(true)
 
 
 
9
  })
10
 
11
  it('renders exactly three TabComponent instances', () => {
 
3
  import MobileNavBar from '@/components/NavBar/MobileNavBar.vue'
4
 
5
  describe('MobileNavBar', () => {
6
+ it('renders a container nav with bg-gray-200 class', () => {
7
  const wrapper = shallowMount(MobileNavBar)
8
+ const nav = wrapper.find('nav.bg-gray-200')
9
+ expect(nav.exists()).toBe(true)
10
+ expect(nav.attributes('data-testid')).toBe('mobile-navbar')
11
+ expect(nav.attributes('aria-label')).toBe('Mobile navigation')
12
  })
13
 
14
  it('renders exactly three TabComponent instances', () => {
static/tests/NavBar.test.ts CHANGED
@@ -3,12 +3,14 @@ import { shallowMount } from '@vue/test-utils'
3
  import NavBar from '@/components/NavBar/NavBar.vue'
4
 
5
  describe('NavBar', () => {
6
- it('renders a fixed-position container div', () => {
7
  const wrapper = shallowMount(NavBar)
8
- const div = wrapper.find('div.fixed')
9
- expect(div.exists()).toBe(true)
10
- expect(div.classes()).toContain('top-2')
11
- expect(div.classes()).toContain('right-5')
 
 
12
  })
13
 
14
  it('renders exactly three TabComponent instances', () => {
 
3
  import NavBar from '@/components/NavBar/NavBar.vue'
4
 
5
  describe('NavBar', () => {
6
+ it('renders a fixed-position container nav', () => {
7
  const wrapper = shallowMount(NavBar)
8
+ const nav = wrapper.find('nav.fixed')
9
+ expect(nav.exists()).toBe(true)
10
+ expect(nav.classes()).toContain('top-2')
11
+ expect(nav.classes()).toContain('right-5')
12
+ expect(nav.attributes('data-testid')).toBe('navbar')
13
+ expect(nav.attributes('aria-label')).toBe('Main navigation')
14
  })
15
 
16
  it('renders exactly three TabComponent instances', () => {