Skip to content

Commit 749ff45

Browse files
Merge branch 'main' into restore-decorator-support_contribute-main
2 parents 43e5f7b + 1995432 commit 749ff45

359 files changed

Lines changed: 84225 additions & 12200 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
"error",
7171
{
7272
"allow": [
73-
"log",
7473
"warn",
7574
"dir",
7675
"timeLog",

.github/workflows/build.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ jobs:
4040
# Project name to use when running "docker compose" prior to e2e tests
4141
COMPOSE_PROJECT_NAME: 'ci'
4242
# Docker Registry to use for Docker compose scripts below.
43-
# We use GitHub's Container Registry to avoid aggressive rate limits at DockerHub.
44-
DOCKER_REGISTRY: ghcr.io
43+
# On the upstream dspace/dspace-angular repository we use GitHub's Container Registry
44+
# (ghcr.io) to avoid aggressive rate limits at DockerHub. Forks cannot authenticate
45+
# against ghcr.io/dspace/* with their own GITHUB_TOKEN (and the images there require
46+
# auth), so on forks we fall back to docker.io where the same images are public.
47+
DOCKER_REGISTRY: ${{ github.repository == 'dspace/dspace-angular' && 'ghcr.io' || 'docker.io' }}
4548
strategy:
4649
# Create a matrix of Node versions to test against (in parallel)
4750
matrix:
@@ -121,9 +124,14 @@ jobs:
121124
path: 'coverage/dspace-angular/lcov.info'
122125
retention-days: 14
123126

124-
# Login to our Docker registry, so that we can access private Docker images using "docker compose" below.
127+
# Login to our Docker registry, so that we can access Docker images using "docker compose" below.
128+
# This login is required on the upstream repository because DOCKER_REGISTRY is set to ghcr.io
129+
# and pulling ghcr.io/dspace/* requires authentication. On forks, DOCKER_REGISTRY falls back to
130+
# docker.io (see env block above) where the same images are publicly pullable without a login,
131+
# and forks cannot authenticate against ghcr.io/dspace/* with their own GITHUB_TOKEN anyway.
125132
- name: Login to ${{ env.DOCKER_REGISTRY }}
126-
uses: docker/login-action@v3
133+
uses: docker/login-action@v4
134+
if: github.repository == 'dspace/dspace-angular'
127135
with:
128136
registry: ${{ env.DOCKER_REGISTRY }}
129137
username: ${{ github.repository_owner }}
@@ -141,7 +149,7 @@ jobs:
141149
# https://github.com/cypress-io/github-action
142150
# (NOTE: to run these e2e tests locally, just use 'ng e2e')
143151
- name: Run e2e tests (integration tests)
144-
uses: cypress-io/github-action@v6
152+
uses: cypress-io/github-action@v7.1.9
145153
with:
146154
# Run tests in Chrome, headless mode (default)
147155
browser: chrome
@@ -314,6 +322,9 @@ jobs:
314322
codecov:
315323
# Must run after 'tests' job above
316324
needs: tests
325+
# Only run on the upstream repository: forks do not have the CODECOV_TOKEN secret,
326+
# and Codecov refuses to create a commit on a protected branch without a token.
327+
if: github.repository == 'dspace/dspace-angular'
317328
runs-on: ubuntu-latest
318329
steps:
319330
- name: Checkout

.github/workflows/docker.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,11 @@ jobs:
106106
sleep 10
107107
docker container ls
108108
# Create a test admin account. Load test data from a simple set of AIPs as defined in cli.ingest.yml
109+
# NOTE: Before creating test data, we wait for the backend to become responsive by requesting it every 10 sec.
110+
# Timeout after 5 minutes. This is done to ensure the backend is fully initialized before we create test data.
109111
- name: Load test data into Backend
110112
run: |
113+
timeout 5m wget --retry-connrefused -t 0 --waitretry=10 http://127.0.0.1:8080/server/api
111114
docker compose -f docker/cli.yml run --rm dspace-cli create-administrator -e test@test.edu -f admin -l user -p admin -c en
112115
docker compose -f docker/cli.yml -f docker/cli.ingest.yml run --rm dspace-cli
113116
# Verify backend started successfully.

.github/workflows/port_merged_pull_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
# Port PR to other branch (ONLY if labeled with "port to")
2828
# See https://github.com/korthout/backport-action
2929
- name: Create backport pull requests
30-
uses: korthout/backport-action@v2
30+
uses: korthout/backport-action@v4
3131
with:
3232
# Trigger based on a "port to [branch]" label on PR
3333
# (This label must specify the branch name to port to)

config/config.example.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ cache:
9393
# NOTE: When updates are made to compiled *.js files, it will automatically bypass this browser cache, because
9494
# all compiled *.js files include a unique hash in their name which updates when content is modified.
9595
control: max-age=604800 # revalidate browser
96+
# These static files should not be cached (paths relative to dist/browser, including the leading slash)
97+
noCacheFiles:
98+
- '/index.html'
9699
autoSync:
97100
defaultTime: 0
98101
maxBufferSize: 100
@@ -516,6 +519,7 @@ themes:
516519
# - name: BASE_THEME_NAME
517520
#
518521
- name: dspace
522+
prefetch: true
519523
headTags:
520524
- tagName: link
521525
attributes:
@@ -794,7 +798,7 @@ addToAnyPlugin:
794798
# 3. You will get a HTML e.g. <a class="a2a_button_facebook"></a> where "facebook" is part you want to include in list
795799
buttons:
796800
- facebook
797-
- twitter
801+
- x
798802
- linkedin
799803
- email
800804
- copy_link

cypress.config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ export default defineConfig({
3737
DSPACE_TEST_SUBMIT_USER_UUID: '914955b1-cf2e-4884-8af7-a166aa24cf73',
3838
DSPACE_TEST_SUBMIT_USER_PASSWORD: 'dspace',
3939
// Administrator users group
40-
DSPACE_ADMINISTRATOR_GROUP: 'e59f5659-bff9-451e-b28f-439e7bd467e4'
40+
DSPACE_ADMINISTRATOR_GROUP: 'e59f5659-bff9-451e-b28f-439e7bd467e4',
41+
//Collection to send and test workflow item
42+
DSPACE_TEST_SUBMIT_WORKFLOW_COLLECTION_NAME: '1-step Workflow collection',
4143
},
4244
e2e: {
4345
// Setup our plugins for e2e tests

cypress/e2e/item-edit.cy.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,27 @@ describe('Edit Item > Edit Metadata tab', () => {
2323
// <ds-edit-item-page> tag must be loaded
2424
cy.get('ds-edit-item-page').should('be.visible');
2525

26+
// wait for all the tabs to be rendered on this page
27+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
28+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
29+
});
30+
2631
// wait for all the ds-dso-edit-metadata-value components to be rendered
2732
cy.get('ds-dso-edit-metadata-value div[role="row"]').each(($row: HTMLDivElement) => {
2833
cy.wrap($row).find('div[role="cell"]').should('be.visible');
2934
});
3035

3136
// Analyze <ds-edit-item-page> for accessibility issues
32-
testA11y('ds-edit-item-page');
37+
testA11y('ds-edit-item-page',
38+
{
39+
rules: {
40+
// Disable flakey "aria-required-children" test. While this test passes when run locally,
41+
// in GitHub CI it will return random failures roughly 1/3 of the time saying that the
42+
// "tablist" doesn't contain required "tab" elements, even though they do exist.
43+
'aria-required-children': { enabled: false },
44+
},
45+
} as Options,
46+
);
3347
});
3448
});
3549

@@ -46,6 +60,11 @@ describe('Edit Item > Status tab', () => {
4660
// <ds-item-status> tag must be loaded
4761
cy.get('ds-item-status').should('be.visible');
4862

63+
// wait for all the tabs to be rendered on this page
64+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
65+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
66+
});
67+
4968
// Analyze for accessibility issues
5069
testA11y('ds-item-status');
5170
});
@@ -64,6 +83,10 @@ describe('Edit Item > Bitstreams tab', () => {
6483
// <ds-item-bitstreams> tag must be loaded
6584
cy.get('ds-item-bitstreams').should('be.visible');
6685

86+
// wait for all the tabs to be rendered on this page
87+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
88+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
89+
});
6790
// Table of item bitstreams must also be loaded
6891
cy.get('div.item-bitstreams').should('be.visible');
6992

@@ -93,6 +116,11 @@ describe('Edit Item > Curate tab', () => {
93116
// <ds-item-curate> tag must be loaded
94117
cy.get('ds-item-curate').should('be.visible');
95118

119+
// wait for all the tabs to be rendered on this page
120+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
121+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
122+
});
123+
96124
// Analyze for accessibility issues
97125
testA11y('ds-item-curate');
98126
});
@@ -111,6 +139,11 @@ describe('Edit Item > Relationships tab', () => {
111139
// <ds-item-relationships> tag must be loaded
112140
cy.get('ds-item-relationships').should('be.visible');
113141

142+
// wait for all the tabs to be rendered on this page
143+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
144+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
145+
});
146+
114147
// Analyze for accessibility issues
115148
testA11y('ds-item-relationships');
116149
});
@@ -129,6 +162,11 @@ describe('Edit Item > Version History tab', () => {
129162
// <ds-item-version-history> tag must be loaded
130163
cy.get('ds-item-version-history').should('be.visible');
131164

165+
// wait for all the tabs to be rendered on this page
166+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
167+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
168+
});
169+
132170
// Analyze for accessibility issues
133171
testA11y('ds-item-version-history');
134172
});
@@ -147,6 +185,11 @@ describe('Edit Item > Access Control tab', () => {
147185
// <ds-item-access-control> tag must be loaded
148186
cy.get('ds-item-access-control').should('be.visible');
149187

188+
// wait for all the tabs to be rendered on this page
189+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
190+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
191+
});
192+
150193
// Analyze for accessibility issues
151194
testA11y('ds-item-access-control');
152195
});
@@ -165,6 +208,11 @@ describe('Edit Item > Collection Mapper tab', () => {
165208
// <ds-item-collection-mapper> tag must be loaded
166209
cy.get('ds-item-collection-mapper').should('be.visible');
167210

211+
// wait for all the tabs to be rendered on this page
212+
cy.get('ds-edit-item-page ul[role="tablist"]').each(($row: HTMLUListElement) => {
213+
cy.wrap($row).find('a[role="tab"]').should('be.visible');
214+
});
215+
168216
// Analyze entire page for accessibility issues
169217
testA11y('ds-item-collection-mapper');
170218

cypress/e2e/my-dspace.cy.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,151 @@ describe('My DSpace page', () => {
131131
testA11y('ds-submission-import-external');
132132
});
133133

134+
it('should let you filter to only archived items', () => {
135+
cy.visit('/mydspace');
136+
137+
//To wait filter be ready
138+
cy.intercept({
139+
method: 'GET',
140+
url: '/server/api/discover/facets/namedresourcetype**',
141+
}).as('facetNamedResourceType');
142+
143+
//This page is restricted, so we will be shown the login form. Fill it in and submit it
144+
cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD'));
145+
146+
//Wait for the page to display
147+
cy.wait('@facetNamedResourceType');
148+
149+
//Open all filters
150+
cy.get('.filter-toggle').click({ multiple: true });
151+
152+
//The authority filter should be visible.
153+
cy.get('ds-search-authority-filter').scrollIntoView().should('be.visible');
154+
155+
//Intercept the request to filter and the request of filter.
156+
cy.intercept({
157+
method: 'GET',
158+
url: '/server/api/discover/search/objects**',
159+
}).as('filterByItem');
160+
161+
//Apply the filter to the “archived” items.
162+
cy.get('ds-search-authority-filter a[href*="f.namedresourcetype=item,authority"]').find('input[type="checkbox"]').click();
163+
164+
//Wait for the response.
165+
cy.wait('@filterByItem');
166+
167+
//Check that we have at least one item and that they all have the archived badge.
168+
cy.get('ds-item-search-result-list-element-submission').should('exist');
169+
cy.get('ds-item-search-result-list-element-submission')
170+
.each(($item) => {
171+
cy.wrap($item)
172+
.find('.badge-archived')
173+
.should('exist');
174+
});
175+
});
176+
177+
//This test also generate an item to validate workflow task section
178+
it('should upload a file via drag & drop, display it in the UI and submit the item', () => {
179+
const fileName = 'example.pdf';
180+
const currentYear = new Date().getFullYear();
181+
182+
cy.visit('/mydspace');
183+
184+
//This page is restricted, so we will be shown the login form. Fill it in and submit it
185+
cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD'));
186+
187+
//Wait for the page to display
188+
cy.get('ds-my-dspace-page').should('be.visible');
189+
190+
//Select the uploader and perform the drag-and-drop action.
191+
cy.get('ds-uploader .well').selectFile(`cypress/fixtures/${fileName}`, { action: 'drag-drop' });
192+
193+
//Validate that the file appears in the UI
194+
cy.get('ds-uploader .filename').should('exist').and('contain.text', fileName);
195+
196+
//Validate that there is now exactly 1 file in the queue
197+
cy.get('ds-uploader .upload-item-top').should('have.length', 1);
198+
199+
// This should display the <ds-collection-dropdown> (popup window)
200+
cy.get('ds-collection-dropdown').should('be.visible');
201+
202+
// Type in a known Collection name in the search box
203+
cy.get('ds-collection-dropdown input[type="search"]').type(Cypress.env('DSPACE_TEST_SUBMIT_WORKFLOW_COLLECTION_NAME'));
204+
205+
// Click on the button matching that known Collection name
206+
cy.get('ds-collection-dropdown li[title="'.concat(Cypress.env('DSPACE_TEST_SUBMIT_WORKFLOW_COLLECTION_NAME')).concat('"]')).click();
207+
208+
// New URL should include /workspaceitems, as we've started a new submission
209+
cy.url().should('include', '/workspaceitems');
210+
211+
//Fill required fields
212+
cy.get('#dc_title').type('Workflow test item');
213+
cy.get('#dc_date_issued_year').type(currentYear.toString());
214+
cy.get('input[name="dc.type"]').click();
215+
cy.get('.dropdown-menu').should('be.visible').contains('button', 'Other').click();
216+
cy.get('#granted').check();
217+
218+
//Press deposit button
219+
cy.get('button[data-test="deposit"]').click();
220+
221+
//validate that URL is /mydspace
222+
cy.url().should('include', '/mydspace');
223+
224+
});
225+
226+
it('should let you take task from workflow', () => {
227+
cy.visit('/mydspace');
228+
229+
//This page is restricted, so we will be shown the login form. Fill it in and submit it
230+
cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD'));
231+
232+
//Wait for the page to display
233+
cy.get('ds-my-dspace-page').should('be.visible');
234+
235+
//And wait to list is ready
236+
cy.get('[data-test="objects"]').should('be.visible');
237+
238+
//Intercept to await backend response
239+
cy.intercept({
240+
method: 'GET',
241+
url: '/server/api/discover/search/objects**',
242+
}).as('workflowSearch');
243+
244+
//Change view to see workflow tasks
245+
cy.get('ds-search-switch-configuration select option[data-test="workflow"]')
246+
.should('exist')
247+
.invoke('attr', 'value')
248+
.then(value => {
249+
cy.get('ds-search-switch-configuration select').select(value);
250+
});
251+
252+
//Await backend search response
253+
cy.wait('@workflowSearch');
254+
255+
//Validate URL
256+
cy.url().should('include', 'configuration=workflow');
257+
258+
//Wait to render the list and at leat one item
259+
cy.get('[data-test="list-object"]').should('have.length.greaterThan', 0);
260+
cy.get('[data-test="claim-button"]').should('exist');
261+
262+
//Check that we have at least one item in worflow search, the item have claim-button and can click in it.
263+
cy.get('[data-test="list-object"]')
264+
.then(($items) => {
265+
const itemWithClaim = [...$items].find(item =>
266+
item.querySelector('[data-test="claim-button"]'),
267+
);
268+
cy.wrap(itemWithClaim).should('exist');
269+
cy.wrap(itemWithClaim).as('selectedItem');
270+
cy.wrap(itemWithClaim).within(() => {
271+
cy.get('ds-pool-task-actions').should('exist');
272+
cy.get('[data-test="claim-button"]').click();
273+
});
274+
});
275+
276+
//Finally, when you click the ‘Claim’ button, the actions for the selected item change
277+
cy.get('@selectedItem').within(() => {
278+
cy.get('ds-claimed-task-actions').should('exist');
279+
});
280+
});
134281
});

cypress/fixtures/example.pdf

18.4 KB
Binary file not shown.

cypress/plugins/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module.exports = (on, config) => {
1313
// Define "log" and "table" tasks, used for logging accessibility errors during CI
1414
// Borrowed from https://github.com/component-driven/cypress-axe#in-cypress-plugins-file
1515
log(message: string) {
16-
console.log(message);
16+
console.info(message);
1717
return null;
1818
},
1919
table(message: string) {

0 commit comments

Comments
 (0)