mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
version 1.3.0
version 1.3.0
This commit is contained in:
commit
be14dbb336
@ -37,7 +37,7 @@
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"prefix": "aca",
|
||||
"styles": [
|
||||
"./assets/fonts/material-icons/material-icons.css",
|
||||
"./assets/fonts/muli/muli.css",
|
||||
@ -46,7 +46,8 @@
|
||||
"scripts": [
|
||||
"../node_modules/pdfjs-dist/build/pdf.js",
|
||||
"../node_modules/pdfjs-dist/lib/shared/compatibility.js",
|
||||
"../node_modules/pdfjs-dist/web/pdf_viewer.js"
|
||||
"../node_modules/pdfjs-dist/web/pdf_viewer.js",
|
||||
"../node_modules/moment/min/moment.min.js"
|
||||
],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
|
@ -1,6 +1,7 @@
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
working_directory: ~/alfresco-content-app
|
||||
docker:
|
||||
- image: circleci/node:8-browsers
|
||||
@ -14,3 +15,48 @@ jobs:
|
||||
paths:
|
||||
- "node_modules"
|
||||
- run: xvfb-run -a npm run test:ci
|
||||
lint:
|
||||
working_directory: ~/alfresco-content-app
|
||||
docker:
|
||||
- image: circleci/node:8-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }}
|
||||
- run: npm install
|
||||
- run: npm run lint
|
||||
spellcheck:
|
||||
working_directory: ~/alfresco-content-app
|
||||
docker:
|
||||
- image: circleci/node:8-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }}
|
||||
- run: npm install
|
||||
- run: npm run spellcheck
|
||||
build:
|
||||
working_directory: ~/alfresco-content-app
|
||||
docker:
|
||||
- image: circleci/node:8-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }}
|
||||
- run: npm install
|
||||
- run: npm run build
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- test
|
||||
- lint:
|
||||
requires:
|
||||
- test
|
||||
- spellcheck:
|
||||
requires:
|
||||
- test
|
||||
- build:
|
||||
requires:
|
||||
- test
|
||||
|
5
.env
5
.env
@ -1,5 +0,0 @@
|
||||
ALFRESCO_TAG=6.0.4-ea
|
||||
SHARE_TAG=6.0.a
|
||||
SOLR6_TAG=1.1.0
|
||||
POSTGRES_TAG=10.1
|
||||
ACA_TAG=development
|
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,10 +1,11 @@
|
||||
## PR Checklist
|
||||
Please check if your PR fulfills the following requirements:
|
||||
|
||||
```
|
||||
- [ ] The commit message follows our guidelines: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md#commit
|
||||
- [ ] Tests for the changes have been added (for bug fixes / features)
|
||||
- [ ] Docs have been added / updated (for bug fixes / features)
|
||||
|
||||
```
|
||||
|
||||
## PR Type
|
||||
What kind of change does this PR introduce?
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -34,6 +34,7 @@
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
/www
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
|
13
.travis.yml
13
.travis.yml
@ -1,13 +1,24 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
addons:
|
||||
chrome: stable
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "8"
|
||||
|
||||
before_script:
|
||||
# Disable services enabled by default
|
||||
- sudo /etc/init.d/postgresql stop
|
||||
|
||||
install:
|
||||
- npm install -g npm@latest
|
||||
- npm ci
|
||||
|
||||
script:
|
||||
- npm run test:ci
|
||||
# - docker-compose stop
|
||||
- npm run build && npm run e2e:docker
|
||||
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -1,5 +1,6 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"sidenav"
|
||||
]
|
||||
}
|
||||
"javascript.preferences.quoteStyle": "single",
|
||||
"typescript.preferences.quoteStyle": "single",
|
||||
"javascript.preferences.importModuleSpecifier": "relative",
|
||||
"typescript.preferences.importModuleSpecifier": "relative"
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
FROM nginx:alpine
|
||||
LABEL version="1.2"
|
||||
LABEL version="1.3"
|
||||
LABEL maintainer="Denys Vuika <denys.vuika@alfresco.com>"
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
80
README.md
80
README.md
@ -1,37 +1,54 @@
|
||||
<p align="left"> <img title="Alfresco" src="alfresco.png" alt="Alfresco - make business flow"></p>
|
||||
|
||||
# Alfresco Example Content Application
|
||||
|
||||
<p align="center">
|
||||
<img title="Alfresco" width="250px" src="alfresco.png" alt="Alfresco">
|
||||
</p>
|
||||
|
||||
## Introduction
|
||||
|
||||
The Alfresco Content Application is an example application built using
|
||||
[Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.6.6.
|
||||
[Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli).
|
||||
|
||||
### Who is this example application for
|
||||
|
||||
This example application demonstrates to Angular software engineers
|
||||
how to construct a content application using the Alfresco ADF.
|
||||
This project demonstrates how to construct an application for Alfresco Content Services using the Alfresco ADF and it represents a meaningful composition of ADF components that provide end users with a simple easy to use interface for working with files in the content repository.
|
||||
|
||||
This example application represents a meaningful composition of ADF components that provide end users
|
||||
with a simple and easy to use interface for working with files stored in the Alfresco Content Services repository.
|
||||
### Where to get help
|
||||
There are a number of resources available to help get you started with the Content App and the ADF:
|
||||
* [Content App Documentation](https://alfresco.github.io/alfresco-content-app/)
|
||||
* [Alfresco ADF Documentation](https://alfresco.github.io/adf-component-catalog/)
|
||||
* [Alfresco Community](https://community.alfresco.com/)
|
||||
* [ADF Gitter Channel](https://gitter.im/Alfresco/alfresco-ng2-components)
|
||||
|
||||
[Public documentation](https://alfresco.github.io/alfresco-content-app/)
|
||||
To get help on Angular CLI use ng help or read the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
||||
### Raising issues and feature requests
|
||||
Isuses can be raised in GitHub or in the Alfresco JIRA project.
|
||||
Please include a clear description, steps to reproduce and screenshots where appropriate.All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions will be considered against existing priorities if the use case serves a general-purpose need.
|
||||
|
||||
Log any issues in the ['ACA' JIRA project](https://issues.alfresco.com/jira/projects/ACA),
|
||||
please include a clear description, steps to reproduce and screenshots where appropriate.
|
||||
#### High level features planned for Q3 2018 (July - September)
|
||||
* Library Management - create, find, join and manage file libraries.
|
||||
* Commenting - View and add comments to files and folders
|
||||
* Sharing Files - activate and deactivate shared file both manually and automatically.
|
||||
* Permissions - update file and folder permissions.
|
||||
* Application Extensibility - Extension framework to provide simple ways to extend the application.
|
||||
|
||||
All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions
|
||||
will be considered against existing priorities if the use case serves a general-purpose need.
|
||||
### Want to help?
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing](https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md) and then check out one of our issues in the [Jira](https://issues.alfresco.com/jira/projects/ACA) or [GitHub](https://github.com/Alfresco/alfresco-content-app/issues)
|
||||
|
||||
## Want to help?
|
||||
## Available Features
|
||||
| Feature | Description |
|
||||
|------------------|----------------------------------------------------------------|
|
||||
| Document List | Folder/File browsing of Personal Files, and File Libraries |
|
||||
| Shared Files | Lists all files that have shared. |
|
||||
| Recent Files | List files created and/or modified by the logged users within the last 30 days|
|
||||
| Favorites | Lists all favorited files for the user. |
|
||||
| Trash | Lists all deleted items stored in the trash can, users can restore or permanently remove. Admin user will see items deleted by all users.|
|
||||
| Upload | Files and folders can be uploaded through the New button or by dragging and dropping into the browser.|
|
||||
| Search | Quick search with live results, and full faceted search results page.|
|
||||
| Actions | A number of actions can be performed on files and/or folders, either individually or multiples at a time|
|
||||
| Viewer | Viewing files in natively in the browser, unsupported formats are transformed by the repository |
|
||||
| Metadata | The information drawer can be configured in the app.config.json to display metadata information, by default file the Properties Aspect is shown and images will also include EXIF information.|
|
||||
| Versioning | The version manager provides access and management of previous file versions, and the ability to upload new versions.|
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent!
|
||||
Read up on our guidelines for [contributing][contributing]
|
||||
and then check out one of our issues in the [Jira][jira] or [GitHub][github]
|
||||
|
||||
## Development server
|
||||
|
||||
@ -40,21 +57,38 @@ The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
Use the `--prod` flag for a production build.
|
||||
Run `npm run build` to build the project in the production mode. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
Run `npm test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
Run the local instance of the application packaged into the docker image together with the ACS images:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
npm run start:docker
|
||||
```
|
||||
|
||||
The ACA runs on port 4000 inside the docker container.
|
||||
Run `npm run e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
```sh
|
||||
npm run e2e
|
||||
```
|
||||
|
||||
When testing is over you can stop all corresponding containers:
|
||||
|
||||
```sh
|
||||
npm run stop:docker
|
||||
```
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
||||
[contributing]: ttps://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md
|
||||
[contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md
|
||||
[github]: https://github.com/Alfresco/alfresco-content-app/issues
|
||||
[jira]: https://issues.alfresco.com/jira/projects/ACA
|
||||
|
BIN
alfresco.png
BIN
alfresco.png
Binary file not shown.
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 9.4 KiB |
44
cspell.json
Normal file
44
cspell.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"version": "0.1",
|
||||
"language": "en",
|
||||
"words": [
|
||||
"succes",
|
||||
|
||||
"ngrx",
|
||||
"ngstack",
|
||||
"sidenav",
|
||||
"injectable",
|
||||
"truthy",
|
||||
"cryptodoc",
|
||||
"mysites",
|
||||
"afts",
|
||||
"classlist",
|
||||
"folderlink",
|
||||
"filelink",
|
||||
"datatable",
|
||||
"repo",
|
||||
"snackbar",
|
||||
"promisify",
|
||||
"xdescribe",
|
||||
"unfavorite",
|
||||
"Snackbar",
|
||||
"devtools",
|
||||
|
||||
"unshare",
|
||||
"validators",
|
||||
"guid",
|
||||
"polyfill",
|
||||
"polyfills",
|
||||
"jsonp",
|
||||
"hammerjs",
|
||||
"pdfjs",
|
||||
"xpath",
|
||||
"tooltip",
|
||||
"tooltips",
|
||||
"unindent",
|
||||
"exif"
|
||||
],
|
||||
"dictionaries": [
|
||||
"html"
|
||||
]
|
||||
}
|
@ -2,13 +2,10 @@ version: "3"
|
||||
|
||||
services:
|
||||
alfresco:
|
||||
image: alfresco/alfresco-content-repository-community:${ALFRESCO_TAG}
|
||||
image: alfresco/alfresco-content-repository-community:6.0.7-ga
|
||||
depends_on:
|
||||
- postgres
|
||||
environment:
|
||||
CATALINA_OPTS : "
|
||||
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
|
||||
"
|
||||
JAVA_OPTS : "
|
||||
-Ddb.driver=org.postgresql.Driver
|
||||
-Ddb.username=alfresco
|
||||
@ -19,15 +16,17 @@ services:
|
||||
-Dsolr.secureComms=none
|
||||
-Dsolr.base.url=/solr
|
||||
-Dindex.subsystem.name=solr6
|
||||
-Dshare.host=localhost
|
||||
-Ddeployment.method=DOCKER_COMPOSE
|
||||
-Dcsrf.filter.enabled=false
|
||||
"
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8080:8080 #Browser port
|
||||
- 8000:8000 #Debug port
|
||||
|
||||
share:
|
||||
image: alfresco/alfresco-share:${SHARE_TAG}
|
||||
image: alfresco/alfresco-share:6.0.b
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
@ -39,18 +38,19 @@ services:
|
||||
- 8081:8080
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_TAG}
|
||||
image: postgres:10.1
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=alfresco
|
||||
- POSTGRES_USER=alfresco
|
||||
- POSTGRES_DB=alfresco
|
||||
command: postgres -c max_connections=300 -c log_min_messages=LOG
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
solr6:
|
||||
image: alfresco/alfresco-search-services:${SOLR6_TAG}
|
||||
image: alfresco/alfresco-search-services:1.1.1
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
@ -68,14 +68,14 @@ services:
|
||||
- 8983:8983 #Browser port
|
||||
|
||||
content-app:
|
||||
image: alfresco/alfresco-content-app:${ACA_TAG}
|
||||
image: alfresco/alfresco-content-app:latest
|
||||
build: .
|
||||
depends_on:
|
||||
- alfresco
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 3001:80
|
||||
- 4001:80
|
||||
# volumes:
|
||||
# - ./app.config.json:/usr/share/nginx/html/app.config.json
|
||||
# - ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
@ -83,13 +83,13 @@ services:
|
||||
proxy:
|
||||
image: nginx
|
||||
depends_on:
|
||||
- content-app
|
||||
- content-app
|
||||
volumes:
|
||||
- ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
networks:
|
||||
- internal
|
||||
- internal
|
||||
ports:
|
||||
- 3000:80
|
||||
- 4000:80
|
||||
|
||||
networks:
|
||||
internal:
|
||||
|
@ -1,5 +0,0 @@
|
||||
ALFRESCO_TAG=6.0.4-ea
|
||||
SHARE_TAG=6.0.a
|
||||
SOLR6_TAG=1.1.0
|
||||
POSTGRES_TAG=10.1
|
||||
ACA_TAG=development
|
@ -2,13 +2,10 @@ version: "3"
|
||||
|
||||
services:
|
||||
alfresco:
|
||||
image: alfresco/alfresco-content-repository-community:${ALFRESCO_TAG}
|
||||
image: alfresco/alfresco-content-repository-community:6.0.7-ga
|
||||
depends_on:
|
||||
- postgres
|
||||
environment:
|
||||
CATALINA_OPTS : "
|
||||
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
|
||||
"
|
||||
JAVA_OPTS : "
|
||||
-Ddb.driver=org.postgresql.Driver
|
||||
-Ddb.username=alfresco
|
||||
@ -19,15 +16,17 @@ services:
|
||||
-Dsolr.secureComms=none
|
||||
-Dsolr.base.url=/solr
|
||||
-Dindex.subsystem.name=solr6
|
||||
-Dshare.host=localhost
|
||||
-Ddeployment.method=DOCKER_COMPOSE
|
||||
-Dcsrf.filter.enabled=false
|
||||
"
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8080:8080 #Browser port
|
||||
- 8000:8000 #Debug port
|
||||
|
||||
share:
|
||||
image: alfresco/alfresco-share:${SHARE_TAG}
|
||||
image: alfresco/alfresco-share:6.0.b
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
@ -39,18 +38,19 @@ services:
|
||||
- 8081:8080
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_TAG}
|
||||
image: postgres:10.1
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=alfresco
|
||||
- POSTGRES_USER=alfresco
|
||||
- POSTGRES_DB=alfresco
|
||||
command: postgres -c max_connections=300 -c log_min_messages=LOG
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
solr6:
|
||||
image: alfresco/alfresco-search-services:${SOLR6_TAG}
|
||||
image: alfresco/alfresco-search-services:1.1.1
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
@ -68,7 +68,7 @@ services:
|
||||
- 8983:8983 #Browser port
|
||||
|
||||
content-app:
|
||||
image: alfresco/alfresco-content-app:${ACA_TAG}
|
||||
image: alfresco/alfresco-content-app:master
|
||||
depends_on:
|
||||
- alfresco
|
||||
networks:
|
||||
|
392
docs/README.md
392
docs/README.md
@ -17,35 +17,395 @@ with a simple and easy to use interface for working with files stored in the Alf
|
||||
|
||||
This application uses the latest releases from Alfresco:
|
||||
|
||||
- [Alfresco ADF version 2.3](https://community.alfresco.com/community/application-development-framework/pages/get-started)
|
||||
- [Alfresco Content Services version 5.2.3](https://www.alfresco.com/platform/content-services-ecm)
|
||||
- [Alfresco Community Edition 201802 EA](https://www.alfresco.com/products/community/download)
|
||||
- [Alfresco ADF (2.4.0)](https://community.alfresco.com/community/application-development-framework/pages/get-started)
|
||||
- [Alfresco Content Services (5.2.3)](https://www.alfresco.com/platform/content-services-ecm)
|
||||
or [Alfresco Community Edition (201802 EA)](https://www.alfresco.com/products/community/download)
|
||||
|
||||
<p class="warning">
|
||||
You also need <a href="https://nodejs.org/en/" target="_blank">node.js</a> (8.9.1 or later) installed to build it locally from source code.
|
||||
You also need <a href="https://nodejs.org/en/" target="_blank">node.js</a> (LTS) installed to build it locally from source code.
|
||||
</p>
|
||||
|
||||
The latest version of the Alfresco Content platform is required
|
||||
due to the application using the latest [REST APIs](https://docs.alfresco.com/5.2/pra/1/topics/pra-welcome.html) developments.
|
||||
|
||||
## Contribution Policy
|
||||
## Features
|
||||
|
||||
### How to contribute
|
||||
The concept of this example is a simple user interface which makes accessing files in the Alfresco Content Services repository easy.
|
||||
|
||||
Fork our repository and submit a pull request when your code is ready for review.
|
||||
To be considered the Travis build must be green and all our automation tests must run without regressions.
|
||||
Often Content Management systems provide more capabilities out of the box than most users need;
|
||||
providing too many capabilities to these users prevents them from working efficiently,
|
||||
so they may end up using unsanctioned file management solutions which presents a proliferation of content storage
|
||||
and collaboration solutions as well as compliance issues for organizations.
|
||||
|
||||
### Contribute to the existing code base
|
||||
This application demonstrates how the complexity of Content Management can be simplified
|
||||
using the Alfresco Application Development Framework to easily and quickly create custom solutions for specific user cases.
|
||||
|
||||
What are we reviewing for?
|
||||
### User Interface - layout
|
||||
|
||||
- **License**: Every file should contain the Alfresco LICENSE header, LGPL Licence.
|
||||
- **Tests**: Add unit cases to cover the new behavior, and make sure all the existing tests are still green.
|
||||
- **JS Documentation**: Every class needs to have its own inline jsdoc, this documentation should explain the general purpose of the class and of each method.
|
||||
- **Documentation**: Update the documentation explaining how to use the new functionality, may not be necessary in the cases where change impacts only the CSS style.
|
||||
- **Clean Coding**: Some good rules are enforced by the tslint, but we want also our code to be easy to read. Please avoid comments inside the code or leaving pieces of code commented out.
|
||||
- **Localization**: Your contribution needs to support localization, with all new strings externalized, all translations are inside the i18n. The minimum requirement is English.
|
||||
There are three main areas of the application controlled by the [Layout component](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/layout):
|
||||
|
||||
- [(1) Application Header](#header)
|
||||
- [(2) Side Navigation](#side-navigation)
|
||||
- [(3) Document List](#document-list-layout)
|
||||
|
||||

|
||||
|
||||
### Header
|
||||
|
||||
The application [header](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/header) has three main elements.
|
||||
|
||||
1. [Logo and Color](#logo-and-color)
|
||||
2. [Search](#search)
|
||||
3. [Current User](#current-user)
|
||||
|
||||

|
||||
|
||||
#### Logo and Color
|
||||
|
||||
Logo & app primary color - logo and color are configurable by updating the
|
||||
[app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) file in the root folder of the project.
|
||||
Please refer to the [Application Configuration](/getting-started#application-logo) documentation for more information on how to change the logo and color.
|
||||
|
||||
#### Search
|
||||
|
||||
The application [Search](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/search) -
|
||||
uses the [ADF Search Component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/search)
|
||||
the app provides a 'live' search feature, where users can open files and folders directly from the Search API results.
|
||||
|
||||

|
||||
|
||||
If you type `Enter` in the text input area, you are going to see [Search Results](#search-results) page
|
||||
with advanced filtering and faceted search.
|
||||
|
||||
#### Current User
|
||||
|
||||
[Current User](https://github.com/Alfresco/alfresco-content-app/tree/development/src/app/components/current-user) -
|
||||
displays the user's name, and a menu where users can logout.
|
||||
Optionally through updating the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json)
|
||||
a language switching menu can be displayed.
|
||||
|
||||

|
||||
|
||||
### Side Navigation
|
||||
|
||||
The application [side navigation](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/sidenav) has two features:
|
||||
a button menu and navigation links.
|
||||
|
||||

|
||||
|
||||
#### New button
|
||||
|
||||
The New button displays a menu which provides three actions:
|
||||
|
||||
- Create a new folder - provides a dialog which allows the creation of a new folder, the folder name is mandatory and the description is optional.
|
||||
- Upload a file - invokes the operating system file browser and allows a user to select file(s) to upload into their current location in the content repository.
|
||||
- Upload a folder - invokes the operating system folder browser and allows a user to select a folder to upload to their current location in the content repository.
|
||||
|
||||
When an upload starts the [upload component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/upload)
|
||||
is displayed which shows the user the progress of the uploads they have started.
|
||||
The upload dialog persists on the screen and can be minimized; users are able to continue using the application whilst uploads are in progress
|
||||
and uploads can be canceled which will stop uploads in progress or permanently delete already completed uploads.
|
||||
|
||||

|
||||
|
||||
#### Navigation
|
||||
|
||||
The navigation links are configurable via the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json).
|
||||
Default configuration creates two sections.
|
||||
See [Navigation](/getting-started#navigation) for more information about configuring the side navigation.
|
||||
|
||||
### Document List Layout
|
||||
|
||||
The main area of the application is composed of several individual ADF components:
|
||||
|
||||
- (1) [Breadcrumb](https://alfresco.github.io/adf-component-catalog/components/BreadcrumbComponent.html)
|
||||
- (2) [Toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html)
|
||||
- (3) [Document List](https://alfresco.github.io/adf-component-catalog/components/DocumentListComponent.html)
|
||||
- (4) [Pagination](https://alfresco.github.io/adf-component-catalog/components/PaginationComponent.html)
|
||||
|
||||

|
||||
|
||||
The application has seven different Document List views which share commonalities between each view and subtle differences depending on the content being loaded which are explained below.
|
||||
|
||||
#### Personal Files
|
||||
|
||||
Personal Files retrieves all content from the logged in user's home area (`/User Homes/<username>/`) in the repository;
|
||||
if the user is ‘admin’ who does not have a home folder then the repository root folder is shown.
|
||||
|
||||
Personal Files is the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component,
|
||||
using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes).
|
||||
|
||||
#### File Libraries
|
||||
|
||||
File Libraries retrieves all the sites that the user is a member of including what type of site it is: public, moderated or private.
|
||||
File Libraries is the [Libraries](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/libraries) component,
|
||||
using the [Sites API](https://api-explorer.alfresco.com/api-explorer/#/sites).
|
||||
|
||||
When a user opens one of their sites then the content for the site's document library is shown.
|
||||
To display the files and folders from a site (`/Sites/<siteid>/Document Library/`) the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component,
|
||||
using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes) is used.
|
||||
|
||||
#### Shared Files
|
||||
|
||||
The Shared Files view aggregates all files that have been shared using the QuickShare feature in the content repository.
|
||||
The [Shared Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/shared-files) component uses the [shared-links API](https://api-explorer.alfresco.com/api-explorer/#/shared-links)
|
||||
and includes extra columns to display where the file is
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository and who created the shared link.
|
||||
|
||||
A feature for creating and removing Shared Links will be added in the future.
|
||||
|
||||
#### Recent Files
|
||||
|
||||
The Recent Files view shows all the files that have been created or modified within the last 30 days by the current user.
|
||||
The [Recent Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/recent-files)
|
||||
component uses the Search API to query SOLR for changes made by the user and includes an extra column to display where the file is
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository.
|
||||
|
||||
#### Favorites
|
||||
|
||||
The Favorites view shows all files and folders from the content repository that have been marked as a favorite by the current user.
|
||||
The [Favorites](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/favorites) component uses the
|
||||
[favorites](https://api-explorer.alfresco.com/api-explorer/#/favorites) API to retrieve all the favorite nodes for the user
|
||||
and includes an extra column to display where the file is
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository.
|
||||
|
||||
#### Trash
|
||||
|
||||
The Trash view shows all the items that a user has deleted, admin will see items deleted by all users.
|
||||
The actions available in this view are Restore and Permanently Delete.
|
||||
The [Trashcan](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/trashcan) component uses the
|
||||
[trashcan](https://api-explorer.alfresco.com/api-explorer/#/trashcan) API to retrieve the deleted items
|
||||
and perform the actions requested by the user and includes an extra column to display where the item was
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository before it was deleted.
|
||||
|
||||
#### Search Results
|
||||
|
||||
The Search Results view shows the found items for a search query. It has a custom layout template and users can easily browse the results and perform actions on items.
|
||||
For more information on the [SearchComponent](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/search), please also check this [Search Results](#search-results1) section.
|
||||
|
||||
#### Actions and the Actions Toolbar
|
||||
|
||||
All the views incorporate the [toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html)
|
||||
component from the Alfresco Application Development Framework;
|
||||
apart from the Trash view they all display the following actions when the current user has the necessary permissions,
|
||||
actions are automatically hidden when the user does not have permission.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Action</th>
|
||||
<th>File</th>
|
||||
<th>Folder</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>View</td>
|
||||
<td>
|
||||
Opens the selected file using the <a href="https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/preview" target="_blank">Preview</a> component,
|
||||
where the file cannot be displayed natively in a browser a PDF rendition is obtained from the repository.
|
||||
</td>
|
||||
<td>Not applicable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Download</td>
|
||||
<td>Downloads single files to the user's computer, when multiple files are selected they are compressed into a ZIP and then downloaded.</td>
|
||||
<td>Folders are automatically compressed into a ZIP and then downloaded to the user's computer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Edit</td>
|
||||
<td>Not applicable</td>
|
||||
<td>The folder name and description can be edited in a dialog.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Favorite</td>
|
||||
<td colspan="2">
|
||||
Toggle the favorite mark on or off for files and folders, when multiple items are selected
|
||||
and one or more are not favorites then the mark will be toggled on.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Copy</td>
|
||||
<td colspan="2">
|
||||
Files and folders can be copied to another location in the content repository using the
|
||||
<a href="https://alfresco.github.io/adf-component-catalog/components/ContentNodeSelectorComponent.html" target="_blank">content-node-selector</a> component;
|
||||
once the copy action has completed the user is notified and can undo the action (which permanently deletes the created copies).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Move</td>
|
||||
<td colspan="2">
|
||||
Files and folders can be moved to another location in the content repository using the
|
||||
<a href="https://alfresco.github.io/adf-component-catalog/components/ContentNodeSelectorComponent.html" target="_blank">content-node-selector</a> component;
|
||||
once the move action has completed the user is notified and can undo the action (which moves the items back to the original location).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Delete</td>
|
||||
<td colspan="2">
|
||||
Files and folders can be deleted from their location in the content repository;
|
||||
once the delete action has completed the user is notified and can undo the action (which restores the items from the trash).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Manage Versions</td>
|
||||
<td>
|
||||
Versions of files can be viewed, uploaded, restored, downloaded and deleted by using the version manager dialog;
|
||||
once each action has completed the list of versions is updated according to the change.
|
||||
</td>
|
||||
<td>Not applicable</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Besides the actions available in the toolbar users can single click an item to select it,
|
||||
or double click on a file to view it, and a folder to open it.
|
||||
|
||||
### File Viewer
|
||||
|
||||
The File Viewer has been created using the [ViewerComponent](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html) from the ADF. The Viewer has four main areas:
|
||||
|
||||

|
||||
|
||||
1. [Header & Toolbar](#header-and-toolbar)
|
||||
2. [Content](#content)
|
||||
3. [Thumbnails side pane](#thumbnails-side-pane)
|
||||
4. [Viewer Controls](#viewer-controls)
|
||||
|
||||
#### Header and Toolbar
|
||||
|
||||
The Header & Toolbar section of the viewer contains a number of features that relate to the file currently being displayed:
|
||||
|
||||
- Close 'X' will return the user to the folder that contains the file.
|
||||
- The name and file type icon is shown in the middle.
|
||||
- Next and previous buttons will be displayed either side of the file name so that users can navigate to other files in the folder without navigating away from the viewer.
|
||||
- Finally, on the right hand side an actions toolbar provides users with the ability to download, favorite, move, copy, delete, manage versions and view info panel.
|
||||
|
||||
#### Content
|
||||
|
||||
The File Viewer consists of four separate views that handle displaying the content based on four types of content, covering various [file/mime](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html#supported-file-formats) types:
|
||||
|
||||
- Document View: PDFs are displayed in the application File Viewer, for other document types (DOCX etc) then a PDF rendition is automatically retrieved.
|
||||
- Image View: JPEG, PNG, GIF, BMP and SVG images are natively displayed in the application File Viewer.
|
||||
- Media View: MP4, MP3, WAV, OGG and WEBM files are played natively application File Viewer. The File Viewer will download, by default, 50MB of the content at a time to ensure a smooth playback of the content.
|
||||
- Text View: TXT, XML, JS, HTML, JSON and TS files are natively displayed as text in the application File Viewer.
|
||||
|
||||
#### Thumbnails side pane
|
||||
|
||||
The Document View includes a thumbnails pane which can be activated by a button in the Viewer Actions toolbar. Clicking on a thumbnail will take a user directly to the selected page and as users scroll through a document the current page is highlighted in the pane.
|
||||
|
||||
#### Viewer Controls
|
||||
|
||||
At the bottom of the content the Viewer Controls allow users to interact with the content in various ways; the actions available are dependant on the type of content being displayed.
|
||||
|
||||
- Document View:
|
||||
- Activate/Deactivate thumbnails pane
|
||||
- Previous/Next page
|
||||
- Jump to page number
|
||||
- Zoom in/out
|
||||
- Fit to page
|
||||
- Image View:
|
||||
- Zoom in/out
|
||||
- Rotate left/right (does not alter content in the repository)
|
||||
- Reset image
|
||||
- Media View:
|
||||
- Play/pause
|
||||
- Timeline position
|
||||
- Audio mute/unmute
|
||||
- Audio volume
|
||||
- Full screen
|
||||
|
||||
### Info Drawer
|
||||
|
||||
The Info Drawer displays node information in the right sidebar panel. It is created by using the [InfoDrawerComponent](https://alfresco.github.io/adf-component-catalog/components/InfoDrawerComponent.html). This info is available for both folder and file nodes.
|
||||
|
||||
Currently, there are 2 tabs available: Properties and Versions.
|
||||
|
||||
#### Properties tab
|
||||
|
||||
The Properties tab displays the node's metadata info by using the [ContentMetadataCardComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataCardComponent.html).
|
||||
|
||||

|
||||
|
||||
For more information, please check also the ADF's [ContentMetadataComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataComponent.html).
|
||||
|
||||
#### Versions tab
|
||||
|
||||
The Versions tab displays info about the node's versions and allows users to [manage versions](#version-manager), according to their permissions. Only the file nodes have version data available.
|
||||
|
||||

|
||||
|
||||
It uses the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html) from ADF framework.
|
||||
Managing versions of a file can be possible also by accessing the 'Manage Versions' option from the 'More actions' menu.
|
||||
|
||||
### Version Manager
|
||||
|
||||
The versions of a file can be viewed & managed by using the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html).
|
||||
|
||||
There are 2 ways users can access the Version Manager:
|
||||
|
||||
1) From the 'Manage Versions' option of the 'More actions' menu (check [Actions and the Actions Toolbar](#actions-and-the-actions-toolbar)):
|
||||
|
||||

|
||||

|
||||
|
||||
2) From the [Info Drawer](#info-drawer) (the Details right panel):
|
||||
|
||||

|
||||
|
||||
#### Upload new version
|
||||
|
||||
A new version for the selected file can be added by using this button. Users can upload a new file version using a file that is does not have the same name, or mimetype as the current version, whilst allowing the user to choose the type of version (minor or major) and inputting supporting comments.
|
||||
Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html).
|
||||
|
||||
#### Actions Menu
|
||||
|
||||
Each item in the version list has a couple of actions available: Restore, Download and Delete. These are displayed if user has permission to do that specific action. The 'Download' and 'Delete' can be also disabled from the app.config.
|
||||
|
||||
In the app.config.json file, these are the current settings for the ACA version manager:
|
||||
|
||||
```json
|
||||
{
|
||||
"adf-version-manager": {
|
||||
"allowComments": true,
|
||||
"allowDownload": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Set the allowComments to false if the version comments should not be displayed on the version list.
|
||||
|
||||
Clicking to delete a version of a file triggers a confirmation dialog. Please see the [ConfirmDialogComponent](https://alfresco.github.io/adf-component-catalog/components/ConfirmDialogComponent.html) for more info.
|
||||
|
||||
### Search Results
|
||||
|
||||
Once you type the text in the Search Input component and press `Enter` you are going to see the Search Results page
|
||||
|
||||

|
||||
|
||||
This page consists of the following ADF components:
|
||||
|
||||
- [Search Filter](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/search-filter.component.md)
|
||||
- [Search Chip List](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/search-chip-list.component.md)
|
||||
- [Search Sorting Picker](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/search-sorting-picker.component.md)
|
||||
- [Document List](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/document-list.component.md) with custom layout template
|
||||
- [Info Drawer](#info-drawer) with Metadata and [Version Management](#version-manager)
|
||||
- [Toolbar with basic actions](#actions-and-the-actions-toolbar) like `Preview`, `Download`, `Favorite`, `Copy`, etc.
|
||||
|
||||
And also the Info Drawer, Toolbar and Node Selector dialogs for copy and move operations.
|
||||
|
||||
## How to contribute
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent!
|
||||
Read up on our guidelines for [contributing][contributing]
|
||||
and then check out one of our issues in the [Jira][jira] or [GitHub][github]
|
||||
|
||||
### How long will it take for my contribution to be reviewed
|
||||
|
||||
The time necessary for a code review will vary, smaller changes may be reviewed within days, while larger changes may take longer.
|
||||
|
||||
[contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md
|
||||
[github]: https://github.com/Alfresco/alfresco-content-app/issues
|
||||
[jira]: https://issues.alfresco.com/jira/projects/ACA
|
||||
|
@ -1,56 +0,0 @@
|
||||
# Building from source code
|
||||
|
||||
The Content App is based on [Angular CLI](https://cli.angular.io), and you can use all the commands, generators and blueprints supported by the CLI.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) 8.9.1 or later LTS version
|
||||
- [Angular CLI](https://cli.angular.io/)
|
||||
|
||||
## Cloning and running
|
||||
|
||||
Use the following commands to clone the project, install dependencies and run it.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Alfresco/alfresco-content-app.git
|
||||
cd alfresco-content-app
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
The application runs at port 4200 by default, and should automatically open in the default browser once project compilation finishes.
|
||||
|
||||
## Proxy settings
|
||||
|
||||
The Content App provides a proxy configuration for local development server
|
||||
that allows you to address specific scenarios with CORS and native authentication dialog.
|
||||
|
||||
You can find settings in the "proxy.conf.js" file in the project root directory.
|
||||
|
||||
<p class="warning">
|
||||
The proxy settings get automatically applied every time you run the application with "npm start" script.
|
||||
You must restart the application every time you change the settings values.
|
||||
</p>
|
||||
|
||||
## Running documentation locally
|
||||
|
||||
For development purposes, you can run and test documentation locally.
|
||||
This is useful when working in different branches instead of a `master` one.
|
||||
|
||||
Run the following command to install the lightweight development server [wsrv](https://denysvuika.gitlab.io/wsrv/#/):
|
||||
|
||||
```sh
|
||||
npm install -g wsrv
|
||||
```
|
||||
|
||||
Now you can use the next command to serve the documentation folder in the browser:
|
||||
|
||||
```sh
|
||||
wsrv docs/ -s -l -o
|
||||
```
|
||||
|
||||
The browser page is going to automatically reload upon changes.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
@ -1,141 +0,0 @@
|
||||
# Application Configuration
|
||||
|
||||
The Content Application provides support for a global settings file `app.config.json` that you can use to customize the behavior of ACA and ADF components.
|
||||
|
||||
## Server settings
|
||||
|
||||
Once the Content Application starts, it needs to know where the Alfresco Content Services (either Community or Enterprise) server is.
|
||||
The "ecmHost" property allows you to set the address of the server using the dynamic or static format.
|
||||
|
||||
### Dynamic address
|
||||
|
||||
The example below demonstrates the most common dynamic format for development environment:
|
||||
|
||||
```json
|
||||
{
|
||||
"ecmHost": "http://{hostname}{:port}",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The configuration above assumes you are running ACS and Content App on the same server and port
|
||||
and allows deploying to different servers having the same unified configuration file.
|
||||
|
||||
For example, a proxy server at `localhost:4200` hosting the Content App as the root application,
|
||||
and `localhost:4200/alfresco` for the ACS repository.
|
||||
|
||||
At runtime, the application is going to automatically substitute the "{hostname}" value with the original hostname.
|
||||
Optionally it can also use the value of the original port if present, for example, "4200" at local machines, or skip the value for port 80.
|
||||
|
||||
### Static address
|
||||
|
||||
Alternatively, you can provide a static address for the ACS server if necessary:
|
||||
|
||||
```json
|
||||
{
|
||||
"ecmHost": "http://localhost:4200",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Application settings
|
||||
|
||||
There are many settings you can change to alter the default behavior of the application.
|
||||
|
||||
### Application Name
|
||||
|
||||
The following block allows you to change the name of the application.
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"application": {
|
||||
"name": "Alfresco Example Content Application"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The value of the `application.name` key gets appended to every browser tab title at runtime
|
||||
with the format `[page title] - [application name]`,
|
||||
for example: "Personal Files - Alfresco Example Content Application".
|
||||
|
||||
### Application Logo
|
||||
|
||||
The default logo displayed in the top left corner of the Alfresco Content Application can be easily changed:
|
||||
|
||||
1. Place your custom logo image file in the [app-name]/src/assets/images folder. The displayed image will resize automatically, an image with extreme width/height might not retain its dimensions.
|
||||
|
||||
2. In the app.config.json file, set the value of the application.logo to contain the name of the custom logo image: "logo": "/assets/images/[image-name].[extension]"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"application": {
|
||||
"logo": "/assets/images/alfresco-logo-white.svg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Header Background color
|
||||
|
||||
You can change the header background color by specifying color code for the "headerColor" key:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"headerColor": "#2196F3"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Restricted content
|
||||
|
||||
You can restrict users from uploading certain types of files and folders by setting or extending the list of rules at the "files.excluded" path.
|
||||
|
||||
By default, the application ships with the following rules already predefined:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"files": {
|
||||
"excluded": [
|
||||
".DS_Store",
|
||||
"desktop.ini",
|
||||
"thumbs.db",
|
||||
".git"
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
<p class="tip">
|
||||
You can get more details on the supported rules in the following article: <a href="https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/upload.service.md" target="_blank">Upload Service</a>.
|
||||
</p>
|
||||
|
||||
### Pagination settings
|
||||
|
||||
You can change the default settings of the pagination that gets applied to all the document lists in the application.
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"pagination": {
|
||||
"supportedPageSizes": [
|
||||
25,
|
||||
50,
|
||||
100
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Your custom settings
|
||||
|
||||
You can store any information in the application configuration file, and access it at runtime by using the `AppConfigService` service provided by ADF.
|
||||
|
||||
<p class="tip">
|
||||
Please refer to the <a href="https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/app-config.service.md" target="_blank">AppConfigService</a> documentation to get more details on Application Configuration features and API available.
|
||||
</p>
|
21
docs/cors.md
21
docs/cors.md
@ -1,21 +0,0 @@
|
||||
# Cross Origin Resource Sharing (CORS)
|
||||
|
||||
## Chrome Workaround
|
||||
|
||||
For the Chrome browser, you can use the following plugin that allows you to toggle CORS:
|
||||
[Allow-Control-Allow-Origin](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi)
|
||||
|
||||
## Firefox Workaround
|
||||
|
||||
Firefox users can try the following plugin: [CORS Everywhere](https://addons.mozilla.org/en-Gb/firefox/addon/cors-everywhere/)
|
||||
|
||||
## Safari Workaround
|
||||
|
||||
If you are developing or testing with Safari then you can use the "Develop" menu to toggle the CORS mode.
|
||||
Please note that the page must be reloaded every time you change CORS settings.
|
||||
|
||||

|
||||
|
||||
## See also
|
||||
|
||||
- [Using CORS](https://www.html5rocks.com/en/tutorials/cors/)
|
143
docs/doc-list.md
143
docs/doc-list.md
@ -1,143 +0,0 @@
|
||||
### Document List Layout
|
||||
|
||||
The main area of the application is composed of several individual ADF components:
|
||||
|
||||
- (1) [Breadcrumb](https://alfresco.github.io/adf-component-catalog/components/BreadcrumbComponent.html)
|
||||
- (2) [Toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html)
|
||||
- (3) [Document List](https://alfresco.github.io/adf-component-catalog/components/DocumentListComponent.html)
|
||||
- (4) [Pagination](https://alfresco.github.io/adf-component-catalog/components/PaginationComponent.html)
|
||||
|
||||

|
||||
|
||||
The application has six different Document List views which share commonalities between each view and subtle differences depending on the content being loaded which are explained below.
|
||||
|
||||
#### Personal Files
|
||||
|
||||
Personal Files retrieves all content from the logged in user's home area (`/User Homes/<username>/`) in the repository;
|
||||
if the user is ‘admin’ who does not have a home folder then the repository root folder is shown.
|
||||
|
||||
Personal Files is the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component,
|
||||
using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes).
|
||||
|
||||
#### File Libraries
|
||||
|
||||
File Libraries retrieves all the sites that the user is a member of including what type of site it is: public, moderated or private.
|
||||
File Libraries is the [Libraries](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/libraries) component,
|
||||
using the [Sites API](https://api-explorer.alfresco.com/api-explorer/#/sites).
|
||||
|
||||
When a user opens one of their sites then the content for the site's document library is shown.
|
||||
To display the files and folders from a site (`/Sites/<siteid>/Document Library/`) the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component,
|
||||
using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes) is used.
|
||||
|
||||
#### Shared Files
|
||||
|
||||
The Shared Files view aggregates all files that have been shared using the QuickShare feature in the content repository.
|
||||
The [Shared Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/shared-files) component uses the [shared-links API](https://api-explorer.alfresco.com/api-explorer/#/shared-links)
|
||||
and includes extra columns to display where the file is
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository and who created the shared link.
|
||||
|
||||
A feature for creating and removing Shared Links will be added in the future.
|
||||
|
||||
#### Recent Files
|
||||
|
||||
The Recent Files view shows all the files that have been created or modified within the last 30 days by the current user.
|
||||
The [Recent Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/current-user)
|
||||
component uses the Search API to query SOLR for changes made by the user and includes an extra column to display where the file is
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository.
|
||||
|
||||
#### Favorites
|
||||
|
||||
The Favorites view shows all files and folders from the content repository that have been marked as a favorite by the current user.
|
||||
The [Favorites](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/favorites) component uses the
|
||||
[favorites](https://api-explorer.alfresco.com/api-explorer/#/favorites) API to retrieve all the favorite nodes for the user
|
||||
and includes an extra column to display where the file is
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository.
|
||||
|
||||
#### Trash
|
||||
|
||||
The Trash view shows all the items that a user has deleted, admin will see items deleted by all users.
|
||||
The actions available in this view are Restore and Permanently Delete.
|
||||
The [Trashcan](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/trashcan) component uses the
|
||||
[trashcan](https://api-explorer.alfresco.com/api-explorer/#/trashcan) API to retrieve the deleted items
|
||||
and perform the actions requested by the user and includes an extra column to display where the item was
|
||||
[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link)
|
||||
in the content repository before it was deleted.
|
||||
|
||||
#### Actions and the Actions Toolbar
|
||||
|
||||
All the views incorporate the [toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html)
|
||||
component from the Alfresco Application Development Framework;
|
||||
apart from the Trash view they all display the following actions when the current user has the necessary permissions,
|
||||
actions are automatically hidden when the user does not have permission.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Action</th>
|
||||
<th>File</th>
|
||||
<th>Folder</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>View</td>
|
||||
<td>
|
||||
Opens the selected file using the <a href="https://github.com/Alfresco/alfresco-content-app/tree/development/src/app/components/preview" target="_blank">Preview</a> component,
|
||||
where the file cannot be displayed natively in a browser a PDF rendition is obtained from the repository.
|
||||
</td>
|
||||
<td>Not applicable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Download</td>
|
||||
<td>Downloads single files to the user's computer, when multiple files are selected they are compressed into a ZIP and then downloaded.</td>
|
||||
<td>Folders are automatically compressed into a ZIP and then downloaded to the user's computer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Edit</td>
|
||||
<td>Not applicable</td>
|
||||
<td>The folder name and description can be edited in a dialog.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Favorite</td>
|
||||
<td colspan="2">
|
||||
Toggle the favorite mark on or off for files and folders, when multiple items are selected
|
||||
and one or more are not favorites then the mark will be toggled on.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Copy</td>
|
||||
<td colspan="2">
|
||||
Files and folders can be copied to another location in the content repository using the
|
||||
<a href="https://alfresco.github.io/adf-component-catalog/components/ContentNodeSelectorComponent.html" target="_blank">content-node-selector</a> component;
|
||||
once the copy action has completed the user is notified and can undo the action (which permanently deletes the created copies).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Move</td>
|
||||
<td colspan="2">
|
||||
Files and folders can be moved to another location in the content repository using the
|
||||
<a href="https://alfresco.github.io/adf-component-catalog/components/ContentNodeSelectorComponent.html" target="_blank">content-node-selector</a> component;
|
||||
once the move action has completed the user is notified and can undo the action (which moves the items back to the original location).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Delete</td>
|
||||
<td colspan="2">
|
||||
Files and folders can be deleted from their location in the content repository;
|
||||
once the delete action has completed the user is notified and can undo the action (which restores the items from the trash).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Manage Versions</td>
|
||||
<td>
|
||||
Versions of files can be viewed, uploaded, restored, downloaded and deleted by using the version manager dialog;
|
||||
once each action has completed the list of versions is updated according to the change.
|
||||
</td>
|
||||
<td>Not applicable</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Besides the actions available in the toolbar users can single click an item to select it,
|
||||
or double click on a file to view it, and a folder to open it.
|
158
docs/docker.md
158
docs/docker.md
@ -1,158 +0,0 @@
|
||||
# Using with Docker
|
||||
|
||||
<p class="warning">
|
||||
This article assumes you are familiar with Docker and know how to create images and containers.
|
||||
</p>
|
||||
|
||||
You can create a Docker image to run Alfresco Content App in the container.
|
||||
|
||||
## Using public Docker images
|
||||
|
||||
You can find all latest images for ACA in the [alfresco-content-app]( https://hub.docker.com/r/alfresco/alfresco-content-app/) DockerHub repository.
|
||||
|
||||
### Tags
|
||||
|
||||
- `latest`: latest stable release (`master` branch), available with 1.1 release or later
|
||||
- `development`: most recent code (`development` branch)
|
||||
|
||||
In addition, there are images for feature branches, pull requests and Travis CI builds.
|
||||
|
||||
### Example
|
||||
|
||||
You can run latest `development` build locally with the following command:
|
||||
|
||||
```sh
|
||||
docker run -p 3000:80 alfresco/alfresco-content-app:development
|
||||
```
|
||||
|
||||
The default image expects an ACS 5.2.2 or later running at port `8080`.
|
||||
You may also need CORS settings to be applied for your ACS installation or image.
|
||||
|
||||
## Building from source code
|
||||
|
||||
You need to run the following commands to build the project from the source code:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
That produces a build in the "dist" folder that you can use with a Docker image.
|
||||
|
||||
<p class="tip">
|
||||
Also, you may need to update the `dist/app.config.json` file with the settings relevant to your scenario.
|
||||
</p>
|
||||
|
||||
## Creating an image
|
||||
|
||||
The Content Application provides a "Dockerfile" file in the repository root.
|
||||
You can build the image with the following command:
|
||||
|
||||
```sh
|
||||
docker image build -t content-app .
|
||||
```
|
||||
|
||||
## Running image in a container
|
||||
|
||||
To run the image locally, you can use the following command:
|
||||
|
||||
```sh
|
||||
docker container run -p 8888:80 --rm content-app
|
||||
```
|
||||
|
||||
Navigate to "http://localhost:8888" to access the running application.
|
||||
|
||||
## Docker Compose file
|
||||
|
||||
You can also use the "docker-compose" file for local development and testing.
|
||||
To build and run a container run the following command in the root project folder:
|
||||
|
||||
```sh
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
To perform a cleanup operation, use the next command:
|
||||
|
||||
```sh
|
||||
docker-compose down --rmi all
|
||||
```
|
||||
|
||||
Navigate to "http://localhost:4200" to access the running application.
|
||||
|
||||
<p class="warning">
|
||||
Please keep in mind that you should manually build the project every time you want to publish the image or run it locally with the container.
|
||||
</p>
|
||||
|
||||
## Using with local ACS setup
|
||||
|
||||
If you run ACS at port 8080 as a Docker container (typical development configuration), you can use the following command to build the project before creating an image:
|
||||
|
||||
```sh
|
||||
npm run build:dev
|
||||
```
|
||||
|
||||
The command above updates the "dist/app.config.json" file to point the Content App to "http://localhost:8080" upon startup.
|
||||
Alternatively, you can change the configuration file manually before generating an image.
|
||||
|
||||
So, the development workflow, in this case, is going to be:
|
||||
|
||||
```sh
|
||||
npm run build:dev
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Navigate to "http://localhost:4200" to access the running application.
|
||||
|
||||
To perform a cleanup operation, use the next command:
|
||||
|
||||
```sh
|
||||
docker-compose down --rmi all
|
||||
```
|
||||
|
||||
## Publishing to Docker Hub
|
||||
|
||||
First of all, if you do not have a Docker Hub account, you can register here: https://hub.docker.com/, the registration is absolutely free.
|
||||
|
||||
Next, it is recommended that you get a clean build of the application:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
npm run build:dev
|
||||
```
|
||||
|
||||
The commands above are going to produce a fresh build that is stored in the `dist` folder.
|
||||
At this point, you can make modifications to the final code in the `dist` folder if needed.
|
||||
For example you may want to change the `app.config.json` file content.
|
||||
|
||||
Now you can build your first version of the image:
|
||||
|
||||
```sh
|
||||
docker image build -t myaccount/content-app:1.0 .
|
||||
```
|
||||
|
||||
Where `myaccount` is usually your Docker Hub account name.
|
||||
|
||||
<p class="warning">
|
||||
Please note the ending "." symbol at the end of the command. It instructs the Docker to take current folder where the `Dockerfile` is located.
|
||||
</p>
|
||||
|
||||
To publish the newly created image use the next command:
|
||||
|
||||
```sh
|
||||
docker push myaccount/content-app:1.0
|
||||
```
|
||||
|
||||
## Running from Docker Hub
|
||||
|
||||
To quickly test the published image, or run it on another machine, use the following command:
|
||||
|
||||
```sh
|
||||
docker container run -p 80:80 --rm myaccount/content-app:1.0
|
||||
```
|
||||
|
||||
The `--rm` switch means the Docker will cleanup the container and image data once you stop the process.
|
||||
|
||||
<p class="tip">
|
||||
You may also want to remove your local image before trying out the Docker Hub:<br>
|
||||
`docker image rm myaccount/content-app:1.0`
|
||||
</p>
|
33
docs/faq.md
33
docs/faq.md
@ -1,33 +0,0 @@
|
||||
# Frequently asked questions
|
||||
|
||||
## How do I log an issue (bug, enhancement, feature)?
|
||||
|
||||
Log any issues in the ['ACA' JIRA project](https://issues.alfresco.com/jira/projects/ACA),
|
||||
please include a clear description, steps to reproduce and screenshots where appropriate.
|
||||
All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions
|
||||
will be considered against existing priorities if the use case serves a general-purpose need.
|
||||
|
||||
## Does Alfresco provide customer support for the example content application?
|
||||
|
||||
Alfresco does not provide Customer Support, it is an example application for developers; [Developer Support Services](https://www.alfresco.com/alfresco-developer-support-services) are available from Alfresco.
|
||||
|
||||
## Does this/Will this application replace Alfresco Share?
|
||||
|
||||
This example application is designed to demonstrate how to construct a content application using the Alfresco Application Development Framework,
|
||||
it is not intended to be a replacement for Alfresco Share.
|
||||
|
||||
## Where can I get help building an application?
|
||||
|
||||
See [Where to get help](/?id=where-to-get-help) section.
|
||||
|
||||
## How do I contribute to the project?
|
||||
|
||||
See [Contribution Policy](/?id=contribution-policy) section.
|
||||
|
||||
## What would you like me to contribute?
|
||||
|
||||
Please refer to the ['ACA' JIRA project](https://issues.alfresco.com/jira/projects/ACA) for tickets in the project backlog.
|
||||
|
||||
## How often will this project be updated?
|
||||
|
||||
This project will continue to evolve as the Alfresco ADF evolves, with Alfresco and community developers contributing to its progress.
|
@ -1,19 +0,0 @@
|
||||
# Features
|
||||
## Introduction
|
||||
The concept of this example is a simple user interface which makes accessing files in the Alfresco Content Services repository easy.
|
||||
|
||||
Often Content Management systems provide more capabilities out of the box than most users need;
|
||||
providing too many capabilities to these users prevents them from working efficiently,
|
||||
so they may end up using unsanctioned file management solutions which presents a proliferation of content storage
|
||||
and collaboration solutions as well as compliance issues for organizations.
|
||||
|
||||
This application demonstrates how the complexity of Content Management can be simplified
|
||||
using the Alfresco Application Development Framework to easily and quickly create custom solutions for specific user cases.
|
||||
|
||||
## User Interface - layout
|
||||
There are three main areas of the application controlled by the [Layout component](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/layout):
|
||||
- [(1) Application Header](/header)
|
||||
- [(2) Side Navigation](/side-nav)
|
||||
- [(3) Document List](/doc-list)
|
||||
|
||||

|
@ -1,43 +0,0 @@
|
||||
### File Viewer
|
||||
|
||||
The File Viewer has been created using the [ViewerComponent](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html) from the ADF. The Viewer has four main areas:
|
||||
|
||||

|
||||
|
||||
#### Header & Toolbar (1)
|
||||
The Header & Toolbar section of the viewer contains a number of features that relate to the file currently being displayed:
|
||||
- Close 'X' will return the user to the folder that contains the file.
|
||||
- The name and file type icon is shown in the middle.
|
||||
- Next and previous buttons will be displayed either side of the file name so that users can navigate to other files in the folder without navigating away from the viewer.
|
||||
- Finally, on the right hand side an actions toolbar provides users with the ability to download, favorite, move, copy, delete, manage versions and view info panel.
|
||||
|
||||
#### Content (2)
|
||||
The File Viewer consists of four separate views that handle displaying the content based on four types of content, covering various [file/mime](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html#supported-file-formats) types:
|
||||
|
||||
- Document View: PDFs are displayed in the application File Viewer, for other document types (DOCX etc) then a PDF rendition is automatically retrieved.
|
||||
- Image View: JPEG, PNG, GIF, BMP and SVG images are natively displayed in the application File Viewer.
|
||||
- Media View: MP4, MP3, WAV, OGG and WEBM files are played natively application File Viewer. The File Viewer will download, by default, 50MB of the content at a time to ensure a smooth playback of the content.
|
||||
- Text View: TXT, XML, JS, HTML, JSON and TS files are natively displayed as text in the application File Viewer.
|
||||
|
||||
#### Thumbnails side pane (3)
|
||||
The Document View includes a thumbnails pane which can be activated by a button in the Viewer Actions toolbar. Clicking on a thumbnail will take a user directly to the selected page and as users scroll through a document the current page is highlighted in the pane.
|
||||
|
||||
#### Viewer Controls (4)
|
||||
At the bottom of the content the Viewer Controls allow users to interact with the content in various ways; the actions available are dependant on the type of content being displayed.
|
||||
|
||||
- Document View:
|
||||
- Activate/Deactivate thumbnails pane
|
||||
- Previous/Next page
|
||||
- Jump to page number
|
||||
- Zoom in/out
|
||||
- Fit to page
|
||||
- Image View:
|
||||
- Zoom in/out
|
||||
- Rotate left/right (does not alter content in the repository)
|
||||
- Reset image
|
||||
- Media View:
|
||||
- Play/pause
|
||||
- Timeline position
|
||||
- Audio mute/unmute
|
||||
- Audio volume
|
||||
- Full screen
|
556
docs/getting-started.md
Normal file
556
docs/getting-started.md
Normal file
@ -0,0 +1,556 @@
|
||||
# Getting Started
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This application uses the latest releases from Alfresco:
|
||||
|
||||
- [Alfresco ADF (2.4.0)](https://community.alfresco.com/community/application-development-framework/pages/get-started)
|
||||
- [Alfresco Content Services (5.2.3)](https://www.alfresco.com/platform/content-services-ecm)
|
||||
or [Alfresco Community Edition (201802 EA)](https://www.alfresco.com/products/community/download)
|
||||
|
||||
<p class="warning">
|
||||
You also need <a href="https://nodejs.org/en/" target="_blank">node.js</a> (LTS) installed to build it locally from source code.
|
||||
</p>
|
||||
|
||||
The latest version of the Alfresco Content platform is required
|
||||
due to the application using the latest [REST APIs](https://docs.alfresco.com/5.2/pra/1/topics/pra-welcome.html) developments.
|
||||
|
||||
## Building from source
|
||||
|
||||
The Content App is based on [Angular CLI](https://cli.angular.io), and you can use all the commands, generators and blueprints supported by the CLI.
|
||||
|
||||
### Prerequisites for building
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) LTS
|
||||
- [Angular CLI](https://cli.angular.io/) 1.7.3
|
||||
|
||||
### Cloning and running
|
||||
|
||||
Use the following commands to clone the project, install dependencies and run it.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Alfresco/alfresco-content-app.git
|
||||
cd alfresco-content-app
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
The application runs at port `4200` by default, and should automatically open in the default browser once project compilation finishes.
|
||||
|
||||
### Proxy settings
|
||||
|
||||
The Content App provides a proxy configuration for local development server
|
||||
that allows you to address specific scenarios with CORS and native authentication dialog.
|
||||
|
||||
You can find settings in the "proxy.conf.js" file in the project root directory.
|
||||
|
||||
<p class="warning">
|
||||
The proxy settings get automatically applied every time you run the application with "npm start" script.
|
||||
You must restart the application every time you change the settings values.
|
||||
</p>
|
||||
|
||||
### Running unit tests
|
||||
|
||||
Run `npm test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
The Content Application provides support for the following languages:
|
||||
|
||||
- German (`de`)
|
||||
- English (`en`)
|
||||
- Spanish (`es`)
|
||||
- French (`fr`)
|
||||
- Italian (`it`)
|
||||
- Japanese (`ja`)
|
||||
- Norwegian (`nb`)
|
||||
- Dutch (`nl`)
|
||||
- Brazilian Portuguese (`pt-BR`)
|
||||
- Russian (`ru`)
|
||||
- Simplified Chinese (`zh-CN`)
|
||||
|
||||
The fallback locale is the English one, however current browser language is taken as the default one automatically when the application starts.
|
||||
|
||||
### User-defined language
|
||||
|
||||
You can allow users to set custom language that gets saved to user preferences.
|
||||
The main application menu already has the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/core/language-menu.component.md) component integrated and pre-filled with the supported items.
|
||||
|
||||
To change the default language set edit the `app.config.json` file and add or remove items:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"languages": [
|
||||
{
|
||||
"key": "de",
|
||||
"label": "German"
|
||||
},
|
||||
{
|
||||
"key": "en",
|
||||
"label": "English"
|
||||
},
|
||||
{
|
||||
"key": "es",
|
||||
"label": "Spanish"
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The file is located at the following path: `/src/app.config.json`.
|
||||
|
||||
### Custom languages
|
||||
|
||||
To add a custom language, add a new "JSON" file to the "/src/assets/i18n" folder
|
||||
with the name of the target locale, for instance, a "de.json" for the "German".
|
||||
|
||||
Translate the resource strings based on the default "en.json" file.
|
||||
You can copy the content over to your newly created file and replace English values with translated text.
|
||||
|
||||
```json
|
||||
{
|
||||
"APP": {
|
||||
"SIGN_IN": "Anmelden",
|
||||
"SIGN_OUT": "Abmelden",
|
||||
"NEW_MENU": {
|
||||
"LABEL": "Neu",
|
||||
"MENU_ITEMS": {
|
||||
"CREATE_FOLDER": "Ordner erstellen",
|
||||
"UPLOAD_FILE": "Datei hochladen",
|
||||
"UPLOAD_FOLDER": "Ordner hochladen"
|
||||
},
|
||||
...
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The Content Application automatically bundles your file upon project build.
|
||||
You can test your locale by changing the browser language settings and reloading the page.
|
||||
|
||||
Optionally, you can extend the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/core/language-menu.component.md) component with the newly added language by updating the `app.config.json` file.
|
||||
|
||||
### Customizing ADF translations
|
||||
|
||||
In addition to creating a custom language file for the Content Application,
|
||||
you can also provide translations for the ADF resources.
|
||||
|
||||
Your `/src/assets/i18n/<lang>.json` file can reflect the structure of one of the ADF language files:
|
||||
|
||||
- ADF Core ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/core/i18n/en.json))
|
||||
- ADF Content Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/content-services/i18n/en.json))
|
||||
- ADF Process Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/process-services/i18n/en.json))
|
||||
- ADF Insights ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/insights/i18n/en.json))
|
||||
|
||||
At runtime, the application-level strings have the highest priority.
|
||||
That means you can replace the value of any ADF resource string if needed.
|
||||
|
||||
For example, let's change the title of the "Create Folder" dialog shipped with the ADF.
|
||||
Modify the `/src/assets/i18n/en.json` file and append the "CORE" section like in the example below:
|
||||
|
||||
```json
|
||||
{
|
||||
"APP": {
|
||||
...
|
||||
},
|
||||
"CORE": {
|
||||
"FOLDER_DIALOG": {
|
||||
"CREATE_FOLDER_TITLE": "Custom title"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, if you run the application and click the "New → Create Folder" menu,
|
||||
the title of the dialog should look like the following:
|
||||
|
||||

|
||||
|
||||
### Language picker
|
||||
|
||||
You can enable internal language picker in the `app.config.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
|
||||
"languagePicker": true,
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## CORS
|
||||
|
||||
The ACA already comes with the proxy configuration for Angular CLI to address CORS-related issues for development.
|
||||
Also, the docker images contain Nginx settings needed for CORS when developing and debugging application locally.
|
||||
|
||||
### Chrome Workaround
|
||||
|
||||
For the Chrome browser, you can use the following plugin that allows you to toggle CORS:
|
||||
[Allow-Control-Allow-Origin](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi)
|
||||
|
||||
### Firefox Workaround
|
||||
|
||||
Firefox users can try the following plugin: [CORS Everywhere](https://addons.mozilla.org/en-Gb/firefox/addon/cors-everywhere/)
|
||||
|
||||
### Safari Workaround
|
||||
|
||||
If you are developing or testing with Safari then you can use the "Develop" menu to toggle the CORS mode.
|
||||
Please note that the page must be reloaded every time you change CORS settings.
|
||||
|
||||

|
||||
|
||||
### See also
|
||||
|
||||
- [Using CORS](https://www.html5rocks.com/en/tutorials/cors/)
|
||||
|
||||
## Configuration
|
||||
|
||||
The Content Application provides support for a global settings file `app.config.json` that you can use to customize the behavior of ACA and ADF components.
|
||||
|
||||
### Server settings
|
||||
|
||||
Once the Content Application starts, it needs to know where the Alfresco Content Services (either Community or Enterprise) server is.
|
||||
The "ecmHost" property allows you to set the address of the server using the dynamic or static format.
|
||||
|
||||
#### Dynamic address
|
||||
|
||||
The example below demonstrates the most common dynamic format for development environment:
|
||||
|
||||
```json
|
||||
{
|
||||
"ecmHost": "http://{hostname}{:port}",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The configuration above assumes you are running ACS and Content App on the same server and port
|
||||
and allows deploying to different servers having the same unified configuration file.
|
||||
|
||||
For example, a proxy server at `localhost:4200` hosting the Content App as the root application,
|
||||
and `localhost:4200/alfresco` for the ACS repository.
|
||||
|
||||
At runtime, the application is going to automatically substitute the "{hostname}" value with the original hostname.
|
||||
Optionally it can also use the value of the original port if present, for example, "4200" at local machines, or skip the value for port 80.
|
||||
|
||||
#### Static address
|
||||
|
||||
Alternatively, you can provide a static address for the ACS server if necessary:
|
||||
|
||||
```json
|
||||
{
|
||||
"ecmHost": "http://localhost:4200",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Application settings
|
||||
|
||||
There are many settings you can change to alter the default behavior of the application.
|
||||
|
||||
#### Application Name
|
||||
|
||||
The following block allows you to change the name of the application.
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"application": {
|
||||
"name": "Alfresco Example Content Application"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The value of the `application.name` key gets appended to every browser tab title at runtime
|
||||
with the format `[page title] - [application name]`,
|
||||
for example: "Personal Files - Alfresco Example Content Application".
|
||||
|
||||
#### Application Logo
|
||||
|
||||
The default logo displayed in the top left corner of the Alfresco Content Application can be easily changed:
|
||||
|
||||
1. Place your custom logo image file in the [app-name]/src/assets/images folder. The displayed image will resize automatically, an image with extreme width/height might not retain its dimensions.
|
||||
|
||||
2. In the app.config.json file, set the value of the application.logo to contain the name of the custom logo image: "logo": "/assets/images/[image-name].[extension]"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"application": {
|
||||
"logo": "/assets/images/alfresco-logo-white.svg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Header Background color
|
||||
|
||||
You can change the header background color by specifying color code for the "headerColor" key:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"headerColor": "#2196F3"
|
||||
}
|
||||
```
|
||||
|
||||
#### Restricted content
|
||||
|
||||
You can restrict users from uploading certain types of files and folders by setting or extending the list of rules at the "files.excluded" path.
|
||||
|
||||
By default, the application ships with the following rules already predefined:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"files": {
|
||||
"excluded": [
|
||||
".DS_Store",
|
||||
"desktop.ini",
|
||||
"thumbs.db",
|
||||
".git"
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
<p class="tip">
|
||||
You can get more details on the supported rules in the following article: <a href="https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/core/upload.service.md" target="_blank">Upload Service</a>.
|
||||
</p>
|
||||
|
||||
#### Pagination settings
|
||||
|
||||
You can change the default settings of the pagination that gets applied to all the document lists in the application.
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"pagination": {
|
||||
"supportedPageSizes": [
|
||||
25,
|
||||
50,
|
||||
100
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Your custom settings
|
||||
|
||||
You can store any information in the application configuration file, and access it at runtime by using the `AppConfigService` service provided by ADF.
|
||||
|
||||
<p class="tip">
|
||||
Please refer to the <a href="https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/core/app-config.service.md" target="_blank">AppConfigService</a> documentation to get more details on Application Configuration features and API available.
|
||||
</p>
|
||||
|
||||
## Navigation
|
||||
|
||||
The Alfresco Content Application provides the following navigation links:
|
||||
|
||||
- Personal Files
|
||||
- File Libraries
|
||||
- Shared
|
||||
- Recent Files
|
||||
- Favorites
|
||||
- Trash
|
||||
|
||||
The side navigation provides support to customize the appearance of the links by editing the `app.config.json`.
|
||||
|
||||
### Customization
|
||||
|
||||
Navigation configuration supports array and object like schema. Defining an object helps navigation to render visual delimiters between different groups of links.
|
||||
|
||||
```json
|
||||
{
|
||||
"navigation": {
|
||||
"main": [
|
||||
...
|
||||
],
|
||||
"secondary": [
|
||||
...
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
```json
|
||||
{
|
||||
"navigation": [
|
||||
{ ... },
|
||||
{ ... },
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### Customize icons and text
|
||||
|
||||
`icon` - supported value can be anything from [Material Design](https://material.io/icons) icons library. If not defined, the link will render just the label value.
|
||||
|
||||
`title` - instructs the link to render a native browser tooltip with the given value. It can be a string or a i18n defined reference. If not defined, the link will not show a tooltip.
|
||||
|
||||
`label` - represents the visual name of the link. It can be a string or a i18n defined reference.
|
||||
|
||||
<p class="danger">
|
||||
Changing ` "route": { "url": "/..." } ` value will affect the navigation since these are mapped to application routing system.
|
||||
</p>
|
||||
|
||||
#### Custom text (i18n)
|
||||
|
||||
To change the `title` and `label` of navigation links edit the values under `BROWSE` entry found at `/src/assets/i18n/en.json`
|
||||
|
||||
```json
|
||||
"APP" : {
|
||||
...
|
||||
"BROWSE": {
|
||||
"PERSONAL": {
|
||||
"TITLE": "Personal Files",
|
||||
"SIDENAV_LINK": {
|
||||
"LABEL": "Personal Files",
|
||||
"TOOLTIP": "View your Personal Files"
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more information about internationalization see [Internationalization (i18n)](#internationalization-i18n) section.
|
||||
|
||||
### User-defined navigation
|
||||
|
||||
To add custom navigation link for the application, first we need to create a component.
|
||||
|
||||
`src/app/components/custom-page/custom-page.component.ts`
|
||||
|
||||
```js
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h4>{{ title }}</h4>
|
||||
`
|
||||
})
|
||||
export class CustomPage {
|
||||
title = 'My Custom Page'
|
||||
}
|
||||
```
|
||||
|
||||
Register the component in ```app.module.ts```
|
||||
|
||||
```javascript
|
||||
|
||||
...
|
||||
import { CustomPage } from './components/custom-page/custom-page.component';
|
||||
|
||||
@NgModule({
|
||||
...
|
||||
declarations: [
|
||||
...,
|
||||
CustomPage
|
||||
],
|
||||
...
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
In the `app.config.json` define a link entry which will point to the custom page
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"navigation": [
|
||||
"main": [ ... ],
|
||||
"secondary": [ ... ],
|
||||
"custom": [
|
||||
{
|
||||
"icon": "work",
|
||||
"label": "Link",
|
||||
"title": "My custome link",
|
||||
"route": {
|
||||
"url": "/custom-route"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Map the `/custom-route` in `app.routes.ts` as a child of `LayoutComponent` definition.
|
||||
|
||||
```js
|
||||
|
||||
import { CustomPage } from './components/custom-page/custom-page.component.ts';
|
||||
|
||||
...
|
||||
{
|
||||
path: '',
|
||||
component: LayoutComponent,
|
||||
children: [
|
||||
...,
|
||||
{
|
||||
path: 'custom-route',
|
||||
component: CustomPage
|
||||
}
|
||||
]
|
||||
}
|
||||
...,
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
For more information about the content of a custom page see [Document List Layout](/#document-list-layout) section.
|
||||
|
||||
## Docker
|
||||
|
||||
The ACA comes with the ACS 6.0 Community Edition preconfigured.
|
||||
The application runs in to modes:
|
||||
|
||||
- Development (runs latest source code, requires building application)
|
||||
- Preview (runs with latest published containers, master branch)
|
||||
|
||||
### Development Mode
|
||||
|
||||
Run the local instance of the application packaged into the docker image together with the ACS images:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
npm run start:docker
|
||||
```
|
||||
|
||||
The ACA runs on port `4000` when served from within container.
|
||||
|
||||
Use the following command to stop all the containers:
|
||||
|
||||
```sh
|
||||
npm run stop:docker
|
||||
```
|
||||
|
||||
### Preview Mode
|
||||
|
||||
<p class="tip">
|
||||
With this mode, you do not need building application from source code or installing dependencies.
|
||||
</p>
|
||||
|
||||
To run the latest published container go to the `docker-compose` folder and start docker compose from there:
|
||||
|
||||
```sh
|
||||
cd docker-compose
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
The application is available at the `http://localhost:3000` address.
|
@ -1,25 +0,0 @@
|
||||
## Header
|
||||
|
||||
The application [header](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/header) has three main elements.
|
||||
|
||||

|
||||
|
||||
### (1) Logo and Color
|
||||
Logo & app primary color - logo and color are configurable by updating the
|
||||
[app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) file in the root folder of the project.
|
||||
Please refer to the [Application Configuration](https://github.com/Alfresco/alfresco-content-app/blob/master/docs/configuration.md#application-logo) documentation for more information on how to change the logo and color.
|
||||
|
||||
### (2) Search
|
||||
The application [Search](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/search) -
|
||||
uses the [ADF Search Component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/search)
|
||||
the app provides a 'live' search feature, where users can open files and folders directly from the Search API results.
|
||||
|
||||

|
||||
|
||||
### (3) Current User
|
||||
[Current User](https://github.com/Alfresco/alfresco-content-app/tree/development/src/app/components/current-user) -
|
||||
displays the user's name, and a menu where users can logout.
|
||||
Optionally through updating the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json)
|
||||
a language switching menu can be displayed.
|
||||
|
||||

|
29
docs/help.md
29
docs/help.md
@ -32,11 +32,30 @@ The most cost-effective way to take advantage of this valuable training is throu
|
||||
Visit the Alfresco University section on the Alfresco website for more information:
|
||||
https://www.alfresco.com/alfresco-university
|
||||
|
||||
# Building and running locally
|
||||
## Frequently asked questions
|
||||
|
||||
Please refer to the [developer docs](/build) to get more details on building and running application on your local machine.
|
||||
### How do I log an issue (bug, enhancement, feature)?
|
||||
|
||||
# Using with Docker
|
||||
Log any issues in the [Jira][jira],
|
||||
please include a clear description, steps to reproduce and screenshots where appropriate.
|
||||
All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions
|
||||
will be considered against existing priorities if the use case serves a general-purpose need.
|
||||
|
||||
The Content App provides a "Dockerfile" and "docker-compose" files to aid in running application in a container.
|
||||
Please refer to the "[Using with Docker](/docker)" article for more details.
|
||||
### Does this/Will this application replace Alfresco Share?
|
||||
|
||||
This example application is designed to demonstrate how to construct a content application using the Alfresco Application Development Framework,
|
||||
it is not intended to be a replacement for Alfresco Share.
|
||||
|
||||
### How do I contribute to the project?
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent!
|
||||
Read up on our guidelines for [contributing][contributing]
|
||||
and then check out one of our issues in the [Jira][jira] or [GitHub][github]
|
||||
|
||||
### How often will this project be updated?
|
||||
|
||||
This project will continue to evolve as the Alfresco ADF evolves, with Alfresco and community developers contributing to its progress.
|
||||
|
||||
[contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md
|
||||
[github]: https://github.com/Alfresco/alfresco-content-app/issues
|
||||
[jira]: https://issues.alfresco.com/jira/projects/ACA
|
||||
|
131
docs/i18n.md
131
docs/i18n.md
@ -1,131 +0,0 @@
|
||||
# Internationalization (i18n)
|
||||
|
||||
The Content Application provides support for the following languages:
|
||||
|
||||
- German (`de`)
|
||||
- English (`en`)
|
||||
- Spanish (`es`)
|
||||
- French (`fr`)
|
||||
- Italian (`it`)
|
||||
- Japanese (`ja`)
|
||||
- Norwegian (`nb`)
|
||||
- Dutch (`nl`)
|
||||
- Brazilian Portuguese (`pt-BR`)
|
||||
- Russian (`ru`)
|
||||
- Simplified Chinese (`zh-CN`)
|
||||
|
||||
The fallback locale is the English one, however current browser language is taken as the default one automatically when the application starts.
|
||||
|
||||
## User-defined language
|
||||
|
||||
You can allow users to set custom language that gets saved to user preferences.
|
||||
The main application menu already has the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/development/docs/language-menu.component.md) component integrated and pre-filled with the supported items.
|
||||
|
||||
To change the default language set edit the `app.config.json` file and add or remove items:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"languages": [
|
||||
{
|
||||
"key": "de",
|
||||
"label": "German"
|
||||
},
|
||||
{
|
||||
"key": "en",
|
||||
"label": "English"
|
||||
},
|
||||
{
|
||||
"key": "es",
|
||||
"label": "Spanish"
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The file is located at the following path: `/src/app.config.json`.
|
||||
|
||||
## Custom languages
|
||||
|
||||
To add a custom language, add a new "JSON" file to the "/src/assets/i18n" folder
|
||||
with the name of the target locale, for instance, a "de.json" for the "German".
|
||||
|
||||
Translate the resource strings based on the default "en.json" file.
|
||||
You can copy the content over to your newly created file and replace English values with translated text.
|
||||
|
||||
```json
|
||||
{
|
||||
"APP": {
|
||||
"SIGN_IN": "Anmelden",
|
||||
"SIGN_OUT": "Abmelden",
|
||||
"NEW_MENU": {
|
||||
"LABEL": "Neu",
|
||||
"MENU_ITEMS": {
|
||||
"CREATE_FOLDER": "Ordner erstellen",
|
||||
"UPLOAD_FILE": "Datei hochladen",
|
||||
"UPLOAD_FOLDER": "Ordner hochladen"
|
||||
},
|
||||
...
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The Content Application automatically bundles your file upon project build.
|
||||
You can test your locale by changing the browser language settings and reloading the page.
|
||||
|
||||
Optionally, you can extend the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/development/docs/language-menu.component.md) component with the newly added language by updating the `app.config.json` file.
|
||||
|
||||
## Customizing ADF translations
|
||||
|
||||
In addition to creating a custom language file for the Content Application,
|
||||
you can also provide translations for the ADF resources.
|
||||
|
||||
Your `/src/assets/i18n/<lang>.json` file can reflect the structure of one of the ADF language files:
|
||||
|
||||
- ADF Core ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/core/i18n/en.json))
|
||||
- ADF Content Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/content-services/i18n/en.json))
|
||||
- ADF Process Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/process-services/i18n/en.json))
|
||||
- ADF Insights ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/insights/i18n/en.json))
|
||||
|
||||
At runtime, the application-level strings have the highest priority.
|
||||
That means you can replace the value of any ADF resource string if needed.
|
||||
|
||||
For example, let's change the title of the "Create Folder" dialog shipped with the ADF.
|
||||
Modify the `/src/assets/i18n/en.json` file and append the "CORE" section like in the example below:
|
||||
|
||||
```json
|
||||
{
|
||||
"APP": {
|
||||
...
|
||||
},
|
||||
"CORE": {
|
||||
"FOLDER_DIALOG": {
|
||||
"CREATE_FOLDER_TITLE": "Custom title"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, if you run the application and click the "New → Create Folder" menu,
|
||||
the title of the dialog should look like the following:
|
||||
|
||||

|
||||
|
||||
## Language picker
|
||||
|
||||
You can enable internal language picker in the `app.config.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
|
||||
"languagePicker": true,
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||

|
BIN
docs/images/aca-search-results.png
Normal file
BIN
docs/images/aca-search-results.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 390 KiB |
@ -19,76 +19,8 @@
|
||||
path: '/'
|
||||
},
|
||||
{
|
||||
title: 'Features',
|
||||
type: 'dropdown',
|
||||
items: [
|
||||
{
|
||||
title: 'Introduction',
|
||||
path: 'features'
|
||||
},
|
||||
{
|
||||
title: 'Application Header',
|
||||
path: 'header'
|
||||
},
|
||||
{
|
||||
title: 'Side Navigation',
|
||||
path: 'side-nav'
|
||||
},
|
||||
{
|
||||
title: 'Document List',
|
||||
path: 'doc-list'
|
||||
},
|
||||
{
|
||||
title: 'File Viewer',
|
||||
path: 'file-viewer'
|
||||
},
|
||||
{
|
||||
title: 'Info Drawer',
|
||||
path: 'info-drawer'
|
||||
},
|
||||
{
|
||||
title: 'Version Manager',
|
||||
path: 'version-manager'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Building',
|
||||
path: 'build'
|
||||
},
|
||||
{
|
||||
title: 'Docker',
|
||||
path: 'docker'
|
||||
},
|
||||
{
|
||||
title: 'FAQ',
|
||||
path: 'faq'
|
||||
},
|
||||
{
|
||||
title: 'Guides',
|
||||
type: 'dropdown',
|
||||
items: [
|
||||
{
|
||||
title: 'Building',
|
||||
path: 'build'
|
||||
},
|
||||
{
|
||||
title: 'Internationalization (i18n)',
|
||||
path: 'i18n'
|
||||
},
|
||||
{
|
||||
title: 'CORS',
|
||||
path: 'cors'
|
||||
},
|
||||
{
|
||||
title: 'Configuration',
|
||||
path: 'configuration'
|
||||
},
|
||||
{
|
||||
title: 'Navigation',
|
||||
path: 'navigation'
|
||||
}
|
||||
]
|
||||
title: 'Getting Started',
|
||||
path: 'getting-started'
|
||||
},
|
||||
{
|
||||
title: 'Get Help',
|
||||
|
@ -1,23 +0,0 @@
|
||||
### Info Drawer
|
||||
|
||||
The Info Drawer displays node information in the right sidebar panel. It is created by using the [InfoDrawerComponent](https://alfresco.github.io/adf-component-catalog/components/InfoDrawerComponent.html). This info is available for both folder and file nodes.
|
||||
|
||||
Currently, there are 2 tabs available: Properties and Versions.
|
||||
|
||||
#### Properties tab
|
||||
|
||||
The Properties tab displays the node's metadata info by using the [ContentMetadataCardComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataCardComponent.html).
|
||||
|
||||

|
||||
|
||||
For more information, please check also the ADF's [ContentMetadataComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataComponent.html).
|
||||
|
||||
#### Versions tab
|
||||
|
||||
The Versions tab displays info about the node's versions and allows users to [manage versions](/version-manager), according to their permissions. Only the file nodes have version data available.
|
||||
|
||||

|
||||
|
||||
It uses the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html) from ADF framework.
|
||||
|
||||
Managing versions of a file can be possible also by accessing the 'Manage Versions' option from the 'More actions' menu. For more info on manage versions, please check the [version manager](/version-manager) page.
|
@ -1,163 +0,0 @@
|
||||
# Navigation
|
||||
|
||||
The Alfresco Content Application provides the following navigation links:
|
||||
|
||||
- Personal Files
|
||||
- File Libraries
|
||||
- Shared
|
||||
- Recent Files
|
||||
- Favorites
|
||||
- Trash
|
||||
|
||||
The side navigation provides support to customize the appearance of the links by editing the `app.config.json`.
|
||||
|
||||
## Customization
|
||||
|
||||
Navigation configuration supports array and object like schema. Defining an object helps navigation to render visual delimiters between different groups of links.
|
||||
|
||||
```json
|
||||
{
|
||||
"navigation": {
|
||||
"main": [
|
||||
...
|
||||
],
|
||||
"secondary": [
|
||||
...
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
```json
|
||||
{
|
||||
"navigation": [
|
||||
{ ... },
|
||||
{ ... },
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Customize icons and text
|
||||
|
||||
`icon` - supported value can be anything from [Material Design](https://material.io/icons) icons library. If not defined, the link will render just the label value.
|
||||
|
||||
`title` - instructs the link to render a native browser tooltip with the given value. It can be a string or a i18n defined reference. If not defined, the link will not show a tooltip.
|
||||
|
||||
`label` - represents the visual name of the link. It can be a string or a i18n defined reference.
|
||||
|
||||
<p class="danger">
|
||||
Changing ` "route": { "url": "/..." } ` value will affect the navigation since these are mapped to application routing system.
|
||||
</p>
|
||||
|
||||
### Custom text (i18n)
|
||||
|
||||
To change the `title` and `label` of navigation links edit the values under `BROWSE` entry found at `/src/assets/i18n/en.json`
|
||||
|
||||
```json
|
||||
"APP" : {
|
||||
...
|
||||
"BROWSE": {
|
||||
"PERSONAL": {
|
||||
"TITLE": "Personal Files",
|
||||
"SIDENAV_LINK": {
|
||||
"LABEL": "Personal Files",
|
||||
"TOOLTIP": "View your Personal Files"
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more information about internationalization see [Internationalization (i18n)](/i18n) section.
|
||||
|
||||
## User-defined navigation
|
||||
|
||||
To add custom navigation link for the application, first we need to create a component.
|
||||
|
||||
`src/app/components/custom-page/custom-page.component.ts`
|
||||
|
||||
```js
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h4>{{ title }}</h4>
|
||||
`
|
||||
})
|
||||
export class CustomPage {
|
||||
title = 'My Custom Page'
|
||||
}
|
||||
```
|
||||
|
||||
Register the component in ```app.module.ts```
|
||||
|
||||
```javascript
|
||||
|
||||
...
|
||||
import { CustomPage } from './components/custom-page/custom-page.component';
|
||||
|
||||
@NgModule({
|
||||
...
|
||||
declarations: [
|
||||
...,
|
||||
CustomPage
|
||||
],
|
||||
...
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
In the `app.config.json` define a link entry which will point to the custom page
|
||||
|
||||
```json
|
||||
{
|
||||
...,
|
||||
"navigation": [
|
||||
"main": [ ... ],
|
||||
"secondary": [ ... ],
|
||||
"custom": [
|
||||
{
|
||||
"icon": "work",
|
||||
"label": "Link",
|
||||
"title": "My custome link",
|
||||
"route": {
|
||||
"url": "/custom-route"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Map the `/custom-route` in `app.routes.ts` as a child of `LayoutComponent` definition.
|
||||
|
||||
```js
|
||||
|
||||
import { CustomPage } from './components/custom-page/custom-page.component.ts';
|
||||
|
||||
...
|
||||
{
|
||||
path: '',
|
||||
component: LayoutComponent,
|
||||
children: [
|
||||
...,
|
||||
{
|
||||
path: 'custom-route',
|
||||
component: CustomPage
|
||||
}
|
||||
]
|
||||
}
|
||||
...,
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
For more information about the content of a custom page see [Document List Layout](/doc-list) section.
|
@ -1,27 +0,0 @@
|
||||
### Side Nav
|
||||
|
||||
The application [side navigation](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/sidenav) has two features:
|
||||
a button menu and navigation links.
|
||||
|
||||

|
||||
|
||||
#### New button
|
||||
|
||||
The New button displays a menu which provides three actions:
|
||||
|
||||
- Create a new folder - provides a dialog which allows the creation of a new folder, the folder name is mandatory and the description is optional.
|
||||
- Upload a file - invokes the operating system file browser and allows a user to select file(s) to upload into their current location in the content repository.
|
||||
- Upload a folder - invokes the operating system folder browser and allows a user to select a folder to upload to their current location in the content repository.
|
||||
|
||||
When an upload starts the [upload component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/upload)
|
||||
is displayed which shows the user the progress of the uploads they have started.
|
||||
The upload dialog persists on the screen and can be minimized; users are able to continue using the application whilst uploads are in progress
|
||||
and uploads can be canceled which will stop uploads in progress or permanently delete already completed uploads.
|
||||
|
||||

|
||||
|
||||
#### Navigation
|
||||
|
||||
The navigation links are configurable via the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json).
|
||||
Default configuration creates two sections.
|
||||
See [Navigation](/navigation) for more information about configuring the side navigation.
|
@ -1,33 +0,0 @@
|
||||
## Version Manager
|
||||
|
||||
The versions of a file can be viewed & managed by using the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html).
|
||||
|
||||
There are 2 ways users can access the Version Manager:
|
||||
|
||||
1. From the 'Manage Versions' option of the 'More actions' menu (check [Actions and the Actions Toolbar](/doc-list?id=actions-and-the-actions-toolbar)):
|
||||

|
||||

|
||||
|
||||
2. From the [Info Drawer](/info-drawer) (the Details right panel):
|
||||

|
||||
|
||||
### Upload new version
|
||||
|
||||
A new version for the selected file can be added by using this button. There is a restriction currently to only upload files of the same extension as the old version. The new version file will be automatically renamed to have the same name as the old version has. Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html).
|
||||
|
||||
### Actions Menu
|
||||
|
||||
Each item in the version list has a couple of actions available: Restore, Download and Delete. These are displayed if user has permission to do that specific action. The 'Download' and 'Delete' can be also disabled from the app.config.
|
||||
|
||||
In the app.config.json file, these are the current settings for the ACA version manager:
|
||||
```
|
||||
"adf-version-manager": {
|
||||
"allowComments": true,
|
||||
"allowDownload": true,
|
||||
"allowDelete": true
|
||||
},
|
||||
...
|
||||
```
|
||||
Set the allowComments to false if the version comments should not be displayed on the version list.
|
||||
|
||||
Clicking to delete a version of a file triggers a confirmation dialog. Please see the [ConfirmDialogComponent](https://alfresco.github.io/adf-component-catalog/components/ConfirmDialogComponent.html) for more info.
|
43
e2e/components/component.ts
Executable file
43
e2e/components/component.ts
Executable file
@ -0,0 +1,43 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, element, by, ExpectedConditions as EC, browser } from 'protractor';
|
||||
import { BROWSER_WAIT_TIMEOUT } from '../configs';
|
||||
|
||||
export abstract class Component {
|
||||
component: ElementFinder;
|
||||
|
||||
constructor(selector: string, ancestor?: ElementFinder) {
|
||||
const locator = by.css(selector);
|
||||
|
||||
this.component = ancestor
|
||||
? ancestor.element(locator)
|
||||
: element(locator);
|
||||
}
|
||||
|
||||
wait() {
|
||||
return browser.wait(EC.presenceOf(this.component), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
}
|
32
e2e/components/components.ts
Executable file
32
e2e/components/components.ts
Executable file
@ -0,0 +1,32 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from './login/login';
|
||||
export * from './header/header';
|
||||
export * from './header/user-info';
|
||||
export * from './data-table/data-table';
|
||||
export * from './pagination/pagination';
|
||||
export * from './sidenav/sidenav';
|
||||
export * from './toolbar/toolbar';
|
243
e2e/components/data-table/data-table.ts
Executable file
243
e2e/components/data-table/data-table.ts
Executable file
@ -0,0 +1,243 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, ElementArrayFinder, promise, by, browser, ExpectedConditions as EC, protractor } from 'protractor';
|
||||
import { BROWSER_WAIT_TIMEOUT } from '../../configs';
|
||||
import { Component } from '../component';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
export class DataTable extends Component {
|
||||
private static selectors = {
|
||||
root: 'adf-datatable',
|
||||
|
||||
head: '.adf-datatable-header',
|
||||
columnHeader: '.adf-datatable-row .adf-datatable-table-cell-header',
|
||||
sortedColumnHeader: `
|
||||
.adf-data-table__header--sorted-asc,
|
||||
.adf-data-table__header--sorted-desc
|
||||
`,
|
||||
|
||||
body: '.adf-datatable-body',
|
||||
row: '.adf-datatable-row[role]',
|
||||
selectedRow: '.adf-datatable-row.is-selected',
|
||||
cell: '.adf-data-table-cell',
|
||||
locationLink: 'aca-location-link',
|
||||
|
||||
selectedIcon: '.mat-icon',
|
||||
|
||||
emptyListContainer: 'div.adf-no-content-container',
|
||||
emptyFolderDragAndDrop: '.adf-empty-list_template .adf-empty-folder',
|
||||
|
||||
emptyListTitle: '.adf-empty-content__title',
|
||||
emptyListSubtitle: '.adf-empty-content__subtitle',
|
||||
emptyListText: '.adf-empty-content__text'
|
||||
};
|
||||
|
||||
head: ElementFinder = this.component.element(by.css(DataTable.selectors.head));
|
||||
body: ElementFinder = this.component.element(by.css(DataTable.selectors.body));
|
||||
cell = by.css(DataTable.selectors.cell);
|
||||
locationLink = by.css(DataTable.selectors.locationLink);
|
||||
emptyList: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListContainer));
|
||||
emptyFolderDragAndDrop: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyFolderDragAndDrop));
|
||||
emptyListTitle: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListTitle));
|
||||
emptyListSubtitle: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListSubtitle));
|
||||
emptyListText: ElementArrayFinder = this.component.all(by.css(DataTable.selectors.emptyListText));
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(DataTable.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
// Wait methods (waits for elements)
|
||||
waitForHeader() {
|
||||
return browser.wait(EC.presenceOf(this.head), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
waitForEmptyState() {
|
||||
return browser.wait(EC.presenceOf(this.emptyList), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
// Header/Column methods
|
||||
getColumnHeaders(): ElementArrayFinder {
|
||||
const locator = by.css(DataTable.selectors.columnHeader);
|
||||
return this.head.all(locator);
|
||||
}
|
||||
|
||||
getNthColumnHeader(nth: number): ElementFinder {
|
||||
return this.getColumnHeaders().get(nth - 1);
|
||||
}
|
||||
|
||||
getColumnHeaderByLabel(label: string): ElementFinder {
|
||||
const locator = by.cssContainingText(DataTable.selectors.columnHeader, label);
|
||||
return this.head.element(locator);
|
||||
}
|
||||
|
||||
getSortedColumnHeader(): ElementFinder {
|
||||
const locator = by.css(DataTable.selectors.sortedColumnHeader);
|
||||
return this.head.element(locator);
|
||||
}
|
||||
|
||||
getSortingOrder() {
|
||||
return this.getSortedColumnHeader().getAttribute('class')
|
||||
.then(str => {
|
||||
if (str.includes('asc')) {
|
||||
return 'asc';
|
||||
} else {
|
||||
if (str.includes('desc')) {
|
||||
return 'desc';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sortByColumn(columnName: string): promise.Promise<void> {
|
||||
const column = this.getColumnHeaderByLabel(columnName);
|
||||
const click = browser.actions().mouseMove(column).click();
|
||||
|
||||
return click.perform();
|
||||
}
|
||||
|
||||
// Rows methods
|
||||
getRows(): ElementArrayFinder {
|
||||
return this.body.all(by.css(DataTable.selectors.row));
|
||||
}
|
||||
|
||||
getSelectedRows(): ElementArrayFinder {
|
||||
return this.body.all(by.css(DataTable.selectors.selectedRow));
|
||||
}
|
||||
|
||||
countSelectedRows(): promise.Promise<number> {
|
||||
return this.getSelectedRows().count();
|
||||
}
|
||||
|
||||
getNthRow(nth: number): ElementFinder {
|
||||
return this.getRows().get(nth - 1);
|
||||
}
|
||||
|
||||
getRowName(name: string): ElementFinder {
|
||||
return this.body.element(by.cssContainingText(`.adf-data-table-cell span`, name));
|
||||
}
|
||||
|
||||
getItemNameTooltip(name: string): promise.Promise<string> {
|
||||
return this.getRowName(name).getAttribute('title');
|
||||
}
|
||||
|
||||
countRows(): promise.Promise<number> {
|
||||
return this.getRows().count();
|
||||
}
|
||||
|
||||
hasCheckMarkIcon(itemName: string) {
|
||||
return this.getRowName(itemName).element(by.xpath(`./ancestor::div[contains(@class, 'adf-datatable-row')]`))
|
||||
.element(by.css(DataTable.selectors.selectedIcon)).isPresent();
|
||||
}
|
||||
|
||||
// Navigation/selection methods
|
||||
doubleClickOnItemName(name: string): promise.Promise<any> {
|
||||
const dblClick = browser.actions()
|
||||
.mouseMove(this.getRowName(name))
|
||||
.click()
|
||||
.click();
|
||||
|
||||
return dblClick.perform();
|
||||
}
|
||||
|
||||
clickOnItemName(name: string): promise.Promise<any> {
|
||||
const item = this.getRowName(name);
|
||||
return Utils.waitUntilElementClickable(item)
|
||||
.then(() => this.getRowName(name).click());
|
||||
}
|
||||
|
||||
selectMultipleItems(names: string[]): promise.Promise<void> {
|
||||
return this.clearSelection()
|
||||
.then(() => browser.actions().sendKeys(protractor.Key.COMMAND).perform())
|
||||
.then(() => {
|
||||
names.forEach(name => {
|
||||
this.clickOnItemName(name);
|
||||
});
|
||||
})
|
||||
.then(() => browser.actions().sendKeys(protractor.Key.NULL).perform());
|
||||
}
|
||||
|
||||
clearSelection(): promise.Promise<void> {
|
||||
return this.getSelectedRows().count()
|
||||
.then(count => {
|
||||
if (count !== 0) { browser.refresh().then(() => this.waitForHeader()); }
|
||||
});
|
||||
}
|
||||
|
||||
getItemLocation(name: string) {
|
||||
return this.getRowName(name).element(by.xpath(`./ancestor::div[contains(@class, 'adf-datatable-row')]`))
|
||||
.element(this.locationLink);
|
||||
}
|
||||
|
||||
getItemLocationTooltip(name: string): promise.Promise<string> {
|
||||
return this.getItemLocation(name).$('a').getAttribute('title');
|
||||
}
|
||||
|
||||
clickItemLocation(name: string) {
|
||||
return this.getItemLocation(name).click();
|
||||
}
|
||||
|
||||
// empty state methods
|
||||
isEmptyList(): promise.Promise<boolean> {
|
||||
return this.emptyList.isPresent();
|
||||
}
|
||||
|
||||
isEmptyWithDragAndDrop(): promise.Promise<boolean> {
|
||||
return this.emptyFolderDragAndDrop.isDisplayed();
|
||||
}
|
||||
|
||||
getEmptyDragAndDropText(): promise.Promise<string> {
|
||||
return this.isEmptyWithDragAndDrop()
|
||||
.then(() => {
|
||||
return this.emptyFolderDragAndDrop.getText();
|
||||
});
|
||||
}
|
||||
|
||||
getEmptyStateTitle(): promise.Promise<string> {
|
||||
return this.isEmptyList()
|
||||
.then(() => {
|
||||
return this.emptyListTitle.getText();
|
||||
});
|
||||
}
|
||||
|
||||
getEmptyStateSubtitle(): promise.Promise<string> {
|
||||
return this.isEmptyList()
|
||||
.then(() => {
|
||||
return this.emptyListSubtitle.getText();
|
||||
});
|
||||
}
|
||||
|
||||
getEmptyStateText(): promise.Promise<string> {
|
||||
return this.isEmptyList()
|
||||
.then(() => {
|
||||
return this.emptyListText.getText();
|
||||
});
|
||||
}
|
||||
|
||||
getCellsContainingName(name: string) {
|
||||
return this.getRows().all(by.cssContainingText(DataTable.selectors.cell, name))
|
||||
.map(cell => cell.getText());
|
||||
}
|
||||
}
|
108
e2e/components/dialog/create-edit-folder-dialog.ts
Executable file
108
e2e/components/dialog/create-edit-folder-dialog.ts
Executable file
@ -0,0 +1,108 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, by, browser, protractor, ExpectedConditions as EC, promise } from 'protractor';
|
||||
import { BROWSER_WAIT_TIMEOUT } from '../../configs';
|
||||
import { Component } from '../component';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
export class CreateOrEditFolderDialog extends Component {
|
||||
private static selectors = {
|
||||
root: 'adf-folder-dialog',
|
||||
|
||||
title: '.mat-dialog-title',
|
||||
nameInput: 'input[placeholder="Name" i]',
|
||||
descriptionTextArea: 'textarea[placeholder="Description" i]',
|
||||
button: '.mat-dialog-actions button',
|
||||
validationMessage: '.mat-hint span'
|
||||
};
|
||||
|
||||
title: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.title));
|
||||
nameInput: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.nameInput));
|
||||
descriptionTextArea: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.descriptionTextArea));
|
||||
createButton: ElementFinder = this.component.element(by.cssContainingText(CreateOrEditFolderDialog.selectors.button, 'Create'));
|
||||
cancelButton: ElementFinder = this.component.element(by.cssContainingText(CreateOrEditFolderDialog.selectors.button, 'Cancel'));
|
||||
updateButton: ElementFinder = this.component.element(by.cssContainingText(CreateOrEditFolderDialog.selectors.button, 'Update'));
|
||||
validationMessage: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.validationMessage));
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(CreateOrEditFolderDialog.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
waitForDialogToOpen() {
|
||||
return browser.wait(EC.presenceOf(this.title), BROWSER_WAIT_TIMEOUT)
|
||||
.then(() => browser.wait(EC.presenceOf(browser.element(by.css('.cdk-overlay-backdrop'))), BROWSER_WAIT_TIMEOUT));
|
||||
|
||||
}
|
||||
|
||||
waitForDialogToClose() {
|
||||
return browser.wait(EC.stalenessOf(this.title), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
getTitle(): promise.Promise<string> {
|
||||
return this.title.getText();
|
||||
}
|
||||
|
||||
isValidationMessageDisplayed(): promise.Promise<boolean> {
|
||||
return this.validationMessage.isDisplayed();
|
||||
}
|
||||
|
||||
getValidationMessage(): promise.Promise<string> {
|
||||
return this.isValidationMessageDisplayed()
|
||||
.then(() => this.validationMessage.getText());
|
||||
}
|
||||
|
||||
enterName(name: string) {
|
||||
return this.nameInput.clear()
|
||||
// .then(() => this.nameInput.sendKeys(name));
|
||||
.then(() => Utils.typeInField(this.nameInput, name));
|
||||
}
|
||||
|
||||
enterDescription(description: string) {
|
||||
return this.descriptionTextArea.clear()
|
||||
// .then(() => this.descriptionTextArea.sendKeys(description));
|
||||
.then(() => Utils.typeInField(this.descriptionTextArea, description));
|
||||
}
|
||||
|
||||
deleteNameWithBackspace(): promise.Promise<void> {
|
||||
return this.nameInput.clear()
|
||||
.then(() => {
|
||||
return this.nameInput.sendKeys(' ', protractor.Key.CONTROL, 'a', protractor.Key.NULL, protractor.Key.BACK_SPACE);
|
||||
});
|
||||
}
|
||||
|
||||
clickCreate() {
|
||||
return this.createButton.click();
|
||||
}
|
||||
|
||||
clickCancel() {
|
||||
return this.cancelButton.click()
|
||||
.then(() => this.waitForDialogToClose());
|
||||
}
|
||||
|
||||
clickUpdate() {
|
||||
return this.updateButton.click();
|
||||
}
|
||||
}
|
42
e2e/components/header/header.ts
Executable file
42
e2e/components/header/header.ts
Executable file
@ -0,0 +1,42 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, by } from 'protractor';
|
||||
import { Component } from '../component';
|
||||
import { UserInfo } from './user-info';
|
||||
|
||||
export class Header extends Component {
|
||||
private locators = {
|
||||
logoLink: by.css('.app-menu__title'),
|
||||
userInfo: by.css('aca-current-user')
|
||||
};
|
||||
|
||||
logoLink: ElementFinder = this.component.element(this.locators.logoLink);
|
||||
userInfo: UserInfo = new UserInfo(this.component);
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super('aca-header', ancestor);
|
||||
}
|
||||
}
|
64
e2e/components/header/user-info.ts
Executable file
64
e2e/components/header/user-info.ts
Executable file
@ -0,0 +1,64 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, by, promise } from 'protractor';
|
||||
import { Menu } from '../menu/menu';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class UserInfo extends Component {
|
||||
private locators = {
|
||||
avatar: by.css('.current-user__avatar'),
|
||||
fullName: by.css('.current-user__full-name'),
|
||||
menuItems: by.css('[mat-menu-item]')
|
||||
};
|
||||
|
||||
fullName: ElementFinder = this.component.element(this.locators.fullName);
|
||||
avatar: ElementFinder = this.component.element(this.locators.avatar);
|
||||
|
||||
menu: Menu = new Menu();
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super('aca-current-user', ancestor);
|
||||
}
|
||||
|
||||
openMenu(): promise.Promise<Menu> {
|
||||
const { menu, avatar } = this;
|
||||
|
||||
return avatar.click()
|
||||
.then(() => menu.wait())
|
||||
.then(() => menu);
|
||||
}
|
||||
|
||||
get name(): promise.Promise<string> {
|
||||
return this.fullName.getText();
|
||||
}
|
||||
|
||||
signOut(): promise.Promise<void> {
|
||||
return this.openMenu()
|
||||
.then(menu => {
|
||||
menu.clickMenuItem('Sign out');
|
||||
});
|
||||
}
|
||||
}
|
105
e2e/components/login/login.ts
Executable file
105
e2e/components/login/login.ts
Executable file
@ -0,0 +1,105 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { by, ElementFinder, promise } from 'protractor';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class LoginComponent extends Component {
|
||||
static selector = 'adf-login';
|
||||
|
||||
private locators = {
|
||||
usernameInput: by.css('input#username'),
|
||||
passwordInput: by.css('input#password'),
|
||||
passwordVisibility: by.css('.adf-login-password-icon'),
|
||||
submitButton: by.css('button#login-button'),
|
||||
errorMessage: by.css('.login-error-message'),
|
||||
copyright: by.css('.copyright')
|
||||
};
|
||||
|
||||
usernameInput: ElementFinder = this.component.element(this.locators.usernameInput);
|
||||
passwordInput: ElementFinder = this.component.element(this.locators.passwordInput);
|
||||
submitButton: ElementFinder = this.component.element(this.locators.submitButton);
|
||||
errorMessage: ElementFinder = this.component.element(this.locators.errorMessage);
|
||||
copyright: ElementFinder = this.component.element(this.locators.copyright);
|
||||
passwordVisibility: ElementFinder = this.component.element(this.locators.passwordVisibility);
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(LoginComponent.selector, ancestor);
|
||||
}
|
||||
|
||||
enterUsername(username: string): LoginComponent {
|
||||
const { usernameInput } = this;
|
||||
|
||||
usernameInput.clear();
|
||||
usernameInput.sendKeys(username);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
enterPassword(password: string): LoginComponent {
|
||||
const { passwordInput } = this;
|
||||
|
||||
passwordInput.clear();
|
||||
passwordInput.sendKeys(password);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
enterCredentials(username: string, password: string) {
|
||||
this.enterUsername(username).enterPassword(password);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
submit(): promise.Promise<void> {
|
||||
return this.submitButton.click();
|
||||
}
|
||||
|
||||
getPasswordVisibility() {
|
||||
return this.passwordVisibility.getText()
|
||||
.then(text => {
|
||||
if (text.endsWith('visibility_off')) {
|
||||
return false;
|
||||
} else {
|
||||
if (text.endsWith('visibility')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isPasswordShown() {
|
||||
return this.passwordInput.getAttribute('type')
|
||||
.then(type => {
|
||||
if (type === 'text') {
|
||||
return true;
|
||||
} else {
|
||||
if (type === 'password') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
106
e2e/components/menu/menu.ts
Executable file
106
e2e/components/menu/menu.ts
Executable file
@ -0,0 +1,106 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, ElementArrayFinder, by, browser, ExpectedConditions as EC, promise } from 'protractor';
|
||||
import { BROWSER_WAIT_TIMEOUT } from '../../configs';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class Menu extends Component {
|
||||
private static selectors = {
|
||||
root: '.mat-menu-panel',
|
||||
item: '.mat-menu-item',
|
||||
icon: '.mat-icon',
|
||||
uploadFiles: 'input[id="upload-multiple-files"]'
|
||||
};
|
||||
|
||||
items: ElementArrayFinder = this.component.all(by.css(Menu.selectors.item));
|
||||
backdrop: ElementFinder = browser.element(by.css('.cdk-overlay-backdrop'));
|
||||
uploadFiles: ElementFinder = this.component.element(by.css(Menu.selectors.uploadFiles));
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(Menu.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
waitForMenuToOpen() {
|
||||
return browser.wait(EC.presenceOf(browser.element(by.css('.mat-menu-panel'))), BROWSER_WAIT_TIMEOUT)
|
||||
.then(() => browser.wait(EC.presenceOf(browser.element(by.css('.cdk-overlay-backdrop'))), BROWSER_WAIT_TIMEOUT))
|
||||
.then(() => browser.wait(EC.visibilityOf(this.items.get(0)), BROWSER_WAIT_TIMEOUT));
|
||||
}
|
||||
|
||||
waitForMenuToClose() {
|
||||
return browser.wait(EC.not(EC.presenceOf(browser.element(by.css('.mat-menu-panel')))), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
closeMenu() {
|
||||
if (this.backdrop.isPresent()) {
|
||||
return this.backdrop.click();
|
||||
} else {
|
||||
return browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform();
|
||||
}
|
||||
}
|
||||
|
||||
getNthItem(nth: number): ElementFinder {
|
||||
return this.items.get(nth - 1);
|
||||
}
|
||||
|
||||
getItemByLabel(menuItem: string): ElementFinder {
|
||||
return this.component.element(by.cssContainingText(Menu.selectors.item, menuItem));
|
||||
}
|
||||
|
||||
getItemTooltip(menuItem: string): promise.Promise<string> {
|
||||
return this.getItemByLabel(menuItem).getAttribute('title');
|
||||
}
|
||||
|
||||
getItemIconText(menuItem: string) {
|
||||
return this.getItemByLabel(menuItem).element(by.css(Menu.selectors.icon)).getText();
|
||||
|
||||
}
|
||||
|
||||
getItemsCount(): promise.Promise<number> {
|
||||
return this.items.count();
|
||||
}
|
||||
|
||||
clickNthItem(nth: number): promise.Promise<any> {
|
||||
const elem = this.getNthItem(nth);
|
||||
return browser.wait(EC.elementToBeClickable(elem), BROWSER_WAIT_TIMEOUT)
|
||||
.then(() => browser.actions().mouseMove(elem).click().perform())
|
||||
.then(() => this.waitForMenuToClose());
|
||||
}
|
||||
|
||||
clickMenuItem(menuItem: string): promise.Promise<any> {
|
||||
const elem = this.getItemByLabel(menuItem);
|
||||
return browser.wait(EC.elementToBeClickable(elem), BROWSER_WAIT_TIMEOUT)
|
||||
.then(() => elem.click())
|
||||
.then(() => this.waitForMenuToClose());
|
||||
}
|
||||
|
||||
isMenuItemPresent(title: string): promise.Promise<boolean> {
|
||||
return this.component.element(by.cssContainingText(Menu.selectors.item, title)).isPresent();
|
||||
}
|
||||
|
||||
uploadFile() {
|
||||
return this.uploadFiles;
|
||||
}
|
||||
}
|
98
e2e/components/pagination/pagination.ts
Executable file
98
e2e/components/pagination/pagination.ts
Executable file
@ -0,0 +1,98 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, promise, by } from 'protractor';
|
||||
import { Menu } from '../menu/menu';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class Pagination extends Component {
|
||||
private static selectors = {
|
||||
root: 'adf-pagination',
|
||||
range: '.adf-pagination__range',
|
||||
maxItems: '.adf-pagination__max-items',
|
||||
currentPage: '.adf-pagination__current-page',
|
||||
totalPages: '.adf-pagination__total-pages',
|
||||
|
||||
previousButton: '.adf-pagination__previous-button',
|
||||
nextButton: '.adf-pagination__next-button',
|
||||
maxItemsButton: '.adf-pagination__max-items + button[mat-icon-button]',
|
||||
pagesButton: '.adf-pagination__current-page + button[mat-icon-button]'
|
||||
};
|
||||
|
||||
range: ElementFinder = this.component.element(by.css(Pagination.selectors.range));
|
||||
maxItems: ElementFinder = this.component.element(by.css(Pagination.selectors.maxItems));
|
||||
currentPage: ElementFinder = this.component.element(by.css(Pagination.selectors.currentPage));
|
||||
totalPages: ElementFinder = this.component.element(by.css(Pagination.selectors.totalPages));
|
||||
previousButton: ElementFinder = this.component.element(by.css(Pagination.selectors.previousButton));
|
||||
nextButton: ElementFinder = this.component.element(by.css(Pagination.selectors.nextButton));
|
||||
maxItemsButton: ElementFinder = this.component.element(by.css(Pagination.selectors.maxItemsButton));
|
||||
pagesButton: ElementFinder = this.component.element(by.css(Pagination.selectors.pagesButton));
|
||||
|
||||
menu: Menu = new Menu();
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(Pagination.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
openMaxItemsMenu(): promise.Promise<Menu> {
|
||||
const { menu, maxItemsButton } = this;
|
||||
|
||||
return maxItemsButton.click()
|
||||
.then(() => menu.waitForMenuToOpen())
|
||||
.then(() => menu);
|
||||
}
|
||||
|
||||
openCurrentPageMenu(): promise.Promise<Menu> {
|
||||
const { menu, pagesButton } = this;
|
||||
|
||||
return pagesButton.click()
|
||||
.then(() => menu.waitForMenuToOpen())
|
||||
.then(() => menu);
|
||||
}
|
||||
|
||||
getText(elem: ElementFinder) {
|
||||
return elem.getText();
|
||||
}
|
||||
|
||||
resetToDefaultPageSize(): promise.Promise<any> {
|
||||
return this.openMaxItemsMenu()
|
||||
.then(menu => menu.clickMenuItem('25'))
|
||||
.then(() => this.menu.waitForMenuToClose());
|
||||
}
|
||||
|
||||
resetToDefaultPageNumber(): promise.Promise<any> {
|
||||
return this.openCurrentPageMenu()
|
||||
.then(menu => menu.clickMenuItem('1'))
|
||||
.then(() => this.menu.waitForMenuToClose());
|
||||
}
|
||||
|
||||
clickNext(): promise.Promise<any> {
|
||||
return this.nextButton.click();
|
||||
}
|
||||
|
||||
clickPrevious(): promise.Promise<any> {
|
||||
return this.previousButton.click();
|
||||
}
|
||||
}
|
82
e2e/components/sidenav/sidenav.ts
Executable file
82
e2e/components/sidenav/sidenav.ts
Executable file
@ -0,0 +1,82 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, ElementArrayFinder, by, promise } from 'protractor';
|
||||
import { Menu } from '../menu/menu';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class Sidenav extends Component {
|
||||
private static selectors = {
|
||||
root: 'app-sidenav',
|
||||
link: '.sidenav-menu__item',
|
||||
label: '.menu__item--label',
|
||||
activeLink: '.menu__item--active',
|
||||
newButton: '.adf-sidebar-action-menu-button'
|
||||
};
|
||||
|
||||
links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link));
|
||||
activeLink: ElementFinder = this.component.element(by.css(Sidenav.selectors.activeLink));
|
||||
newButton: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.newButton));
|
||||
|
||||
menu: Menu = new Menu();
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(Sidenav.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
openNewMenu(): promise.Promise<Menu> {
|
||||
const { menu, newButton } = this;
|
||||
|
||||
return newButton.click()
|
||||
.then(() => menu.waitForMenuToOpen())
|
||||
.then(() => menu);
|
||||
}
|
||||
|
||||
openCreateDialog(): any {
|
||||
return this.openNewMenu()
|
||||
.then(() => this.menu.clickMenuItem('Create folder'));
|
||||
}
|
||||
|
||||
isActiveByLabel(label: string): promise.Promise<boolean> {
|
||||
return this.getLinkByLabel(label).getAttribute('class')
|
||||
.then(className => className.includes(Sidenav.selectors.activeLink.replace('.', '')));
|
||||
}
|
||||
|
||||
getLink(label: string): ElementFinder {
|
||||
return this.component.element(by.cssContainingText(Sidenav.selectors.link, label));
|
||||
}
|
||||
|
||||
getLinkByLabel(label: string): ElementFinder {
|
||||
return this.component.element(by.cssContainingText(Sidenav.selectors.label, label));
|
||||
}
|
||||
|
||||
getLinkTooltip(label: string): promise.Promise<string> {
|
||||
return this.getLink(label).getAttribute('title');
|
||||
}
|
||||
|
||||
navigateToLinkByLabel(label: string): promise.Promise<any> {
|
||||
return this.getLinkByLabel(label).click();
|
||||
}
|
||||
}
|
64
e2e/components/toolbar/toolbar-actions.ts
Executable file
64
e2e/components/toolbar/toolbar-actions.ts
Executable file
@ -0,0 +1,64 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, ElementArrayFinder, by, promise } from 'protractor';
|
||||
import { Menu } from '../menu/menu';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class ToolbarActions extends Component {
|
||||
private static selectors = {
|
||||
root: 'adf-toolbar',
|
||||
button: '.mat-icon-button'
|
||||
};
|
||||
|
||||
menu: Menu = new Menu();
|
||||
buttons: ElementArrayFinder = this.component.all(by.css(ToolbarActions.selectors.button));
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(ToolbarActions.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
isEmpty(): promise.Promise<boolean> {
|
||||
return this.buttons.count().then(count => (count === 0));
|
||||
}
|
||||
|
||||
isButtonPresent(title: string): promise.Promise<boolean> {
|
||||
return this.component.element(by.css(`${ToolbarActions.selectors.button}[title="${title}"]`)).isPresent();
|
||||
}
|
||||
|
||||
getButtonByLabel(label: string): ElementFinder {
|
||||
return this.component.element(by.cssContainingText(ToolbarActions.selectors.button, label));
|
||||
}
|
||||
|
||||
getButtonByTitleAttribute(title: string): ElementFinder {
|
||||
return this.component.element(by.css(`${ToolbarActions.selectors.button}[title="${title}"]`));
|
||||
}
|
||||
|
||||
openMoreMenu() {
|
||||
return this.getButtonByTitleAttribute('More actions').click()
|
||||
.then(() => this.menu.waitForMenuToOpen())
|
||||
.then(() => this.menu);
|
||||
}
|
||||
}
|
82
e2e/components/toolbar/toolbar-breadcrumb.ts
Executable file
82
e2e/components/toolbar/toolbar-breadcrumb.ts
Executable file
@ -0,0 +1,82 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder, ElementArrayFinder, by, promise } from 'protractor';
|
||||
import { Component } from '../component';
|
||||
|
||||
export class ToolbarBreadcrumb extends Component {
|
||||
private static selectors = {
|
||||
root: 'adf-breadcrumb',
|
||||
item: '.adf-breadcrumb-item',
|
||||
currentItem: '.adf-breadcrumb-item-current'
|
||||
};
|
||||
|
||||
items: ElementArrayFinder = this.component.all(by.css(ToolbarBreadcrumb.selectors.item));
|
||||
currentItem: ElementFinder = this.component.element(by.css(ToolbarBreadcrumb.selectors.currentItem));
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(ToolbarBreadcrumb.selectors.root, ancestor);
|
||||
}
|
||||
|
||||
getNthItem(nth: number): ElementFinder {
|
||||
return this.items.get(nth - 1);
|
||||
}
|
||||
|
||||
getNthItemName(nth: number) {
|
||||
return this.getNthItem(nth).getText();
|
||||
}
|
||||
|
||||
getItemsCount(): promise.Promise<number> {
|
||||
return this.items.count();
|
||||
}
|
||||
|
||||
getAllItems() {
|
||||
return this.items.map(elem => elem.getText().then(str => str.split('\nchevron_right')[0]));
|
||||
}
|
||||
|
||||
getFirstItemName(): promise.Promise<string> {
|
||||
return this.items.get(0).getText();
|
||||
}
|
||||
|
||||
getCurrentItem() {
|
||||
return this.currentItem;
|
||||
}
|
||||
|
||||
getCurrentItemName(): promise.Promise<string> {
|
||||
return this.currentItem.getText();
|
||||
}
|
||||
|
||||
clickItem(name: string) {
|
||||
return this.component.element(by.css(`${ToolbarBreadcrumb.selectors.item}[title=${name}]`)).click();
|
||||
}
|
||||
|
||||
clickNthItem(nth: number) {
|
||||
return this.getNthItem(nth).click();
|
||||
}
|
||||
|
||||
getNthItemTooltip(nth: number) {
|
||||
return this.getNthItem(nth).getAttribute('title');
|
||||
}
|
||||
}
|
42
e2e/components/toolbar/toolbar.ts
Executable file
42
e2e/components/toolbar/toolbar.ts
Executable file
@ -0,0 +1,42 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ElementFinder } from 'protractor';
|
||||
import { Component } from '../component';
|
||||
import { ToolbarActions } from './toolbar-actions';
|
||||
import { ToolbarBreadcrumb } from './toolbar-breadcrumb';
|
||||
|
||||
export class Toolbar extends Component {
|
||||
private static selectors = {
|
||||
root: '.inner-layout__header'
|
||||
};
|
||||
|
||||
actions: ToolbarActions = new ToolbarActions(this.component);
|
||||
breadcrumb: ToolbarBreadcrumb = new ToolbarBreadcrumb(this.component);
|
||||
|
||||
constructor(ancestor?: ElementFinder) {
|
||||
super(Toolbar.selectors.root, ancestor);
|
||||
}
|
||||
}
|
78
e2e/configs.ts
Executable file
78
e2e/configs.ts
Executable file
@ -0,0 +1,78 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const BROWSER_RESOLUTION_WIDTH = 1200;
|
||||
export const BROWSER_RESOLUTION_HEIGHT = 800;
|
||||
|
||||
export const BROWSER_WAIT_TIMEOUT = 30000;
|
||||
|
||||
// Application configs
|
||||
export const APP_HOST = 'http://localhost:3000';
|
||||
|
||||
// Repository configs
|
||||
export const REPO_API_HOST = 'http://localhost:8080';
|
||||
export const REPO_API_TENANT = '-default-';
|
||||
|
||||
// Admin details
|
||||
export const ADMIN_USERNAME = 'admin';
|
||||
export const ADMIN_PASSWORD = 'admin';
|
||||
export const ADMIN_FULL_NAME = 'Administrator';
|
||||
|
||||
// Application Routes
|
||||
export const APP_ROUTES = {
|
||||
FAVORITES: '/favorites',
|
||||
FILE_LIBRARIES: '/libraries',
|
||||
LOGIN: '/login',
|
||||
LOGOUT: '/logout',
|
||||
PERSONAL_FILES: '/personal-files',
|
||||
RECENT_FILES: '/recent-files',
|
||||
SHARED_FILES: '/shared',
|
||||
TRASHCAN: '/trashcan'
|
||||
};
|
||||
|
||||
// Sidebar labels
|
||||
export const SIDEBAR_LABELS = {
|
||||
PERSONAL_FILES: 'Personal Files',
|
||||
FILE_LIBRARIES: 'File Libraries',
|
||||
SHARED_FILES: 'Shared',
|
||||
RECENT_FILES: 'Recent Files',
|
||||
FAVORITES: 'Favorites',
|
||||
TRASH: 'Trash'
|
||||
};
|
||||
|
||||
// Site visibility
|
||||
export const SITE_VISIBILITY = {
|
||||
PUBLIC: 'PUBLIC',
|
||||
MODERATED: 'MODERATED',
|
||||
PRIVATE: 'PRIVATE'
|
||||
};
|
||||
|
||||
// Site roles
|
||||
export const SITE_ROLES = {
|
||||
SITE_CONSUMER: 'SiteConsumer',
|
||||
SITE_COLLABORATOR: 'SiteCollaborator',
|
||||
SITE_CONTRIBUTOR: 'SiteContributor',
|
||||
SITE_MANAGER: 'SiteManager'
|
||||
};
|
40
e2e/pages/browsing-page.ts
Executable file
40
e2e/pages/browsing-page.ts
Executable file
@ -0,0 +1,40 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { promise } from 'protractor';
|
||||
import { Header, DataTable, Pagination, Toolbar, Sidenav } from '../components/components';
|
||||
import { Page } from './page';
|
||||
|
||||
export class BrowsingPage extends Page {
|
||||
header = new Header(this.app);
|
||||
sidenav = new Sidenav(this.app);
|
||||
toolbar = new Toolbar(this.app);
|
||||
dataTable = new DataTable(this.app);
|
||||
pagination = new Pagination(this.app);
|
||||
|
||||
signOut(): promise.Promise<void> {
|
||||
return this.header.userInfo.signOut();
|
||||
}
|
||||
}
|
75
e2e/pages/login-page.ts
Executable file
75
e2e/pages/login-page.ts
Executable file
@ -0,0 +1,75 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { browser, ExpectedConditions as EC, promise } from 'protractor';
|
||||
import { LoginComponent } from '../components/components';
|
||||
import { Page } from './page';
|
||||
import { Utils } from '../utilities/utils';
|
||||
|
||||
import {
|
||||
ADMIN_USERNAME,
|
||||
ADMIN_PASSWORD,
|
||||
BROWSER_WAIT_TIMEOUT,
|
||||
APP_ROUTES
|
||||
} from '../configs';
|
||||
|
||||
export class LoginPage extends Page {
|
||||
login: LoginComponent = new LoginComponent(this.app);
|
||||
|
||||
/** @override */
|
||||
constructor() {
|
||||
super(APP_ROUTES.LOGIN);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
load(): promise.Promise<any> {
|
||||
return super.load().then(() => {
|
||||
const { submitButton } = this.login;
|
||||
const hasSubmitButton = EC.presenceOf(submitButton);
|
||||
|
||||
return browser.wait(hasSubmitButton, BROWSER_WAIT_TIMEOUT)
|
||||
.then(() => Utils.clearLocalStorage())
|
||||
.then(() => browser.manage().deleteAllCookies());
|
||||
});
|
||||
}
|
||||
|
||||
loginWith(username: string, password?: string): promise.Promise<any> {
|
||||
const pass = password || username;
|
||||
return this.load()
|
||||
.then(() => this.login.enterCredentials(username, pass).submit())
|
||||
.then(() => super.waitForApp());
|
||||
}
|
||||
|
||||
loginWithAdmin(): promise.Promise<any> {
|
||||
return this.load()
|
||||
.then(() => this.loginWith(ADMIN_USERNAME, ADMIN_PASSWORD));
|
||||
}
|
||||
|
||||
tryLoginWith(username: string, password?: string): promise.Promise<void> {
|
||||
const pass = password || username;
|
||||
return this.load()
|
||||
.then(() => this.login.enterCredentials(username, pass).submit())
|
||||
.then(() => browser.wait(EC.presenceOf(this.login.errorMessage), BROWSER_WAIT_TIMEOUT));
|
||||
}
|
||||
}
|
43
e2e/pages/logout-page.ts
Executable file
43
e2e/pages/logout-page.ts
Executable file
@ -0,0 +1,43 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { promise } from 'protractor';
|
||||
import { Page } from './page';
|
||||
import { APP_ROUTES } from '../configs';
|
||||
import { Utils } from '../utilities/utils';
|
||||
|
||||
export class LogoutPage extends Page {
|
||||
/** @override */
|
||||
constructor() {
|
||||
super(APP_ROUTES.LOGIN);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
load(): promise.Promise<any> {
|
||||
return Utils.clearLocalStorage()
|
||||
.then(() => Utils.clearSessionStorage())
|
||||
.then(() => super.load());
|
||||
}
|
||||
}
|
110
e2e/pages/page.ts
Executable file
110
e2e/pages/page.ts
Executable file
@ -0,0 +1,110 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser, element, by, ElementFinder, promise, ExpectedConditions as EC } from 'protractor';
|
||||
import { BROWSER_WAIT_TIMEOUT } from './../configs';
|
||||
|
||||
export abstract class Page {
|
||||
private static USE_HASH_STRATEGY = true;
|
||||
|
||||
private locators = {
|
||||
app: by.css('app-root'),
|
||||
layout: by.css('app-layout'),
|
||||
overlay: by.css('.cdk-overlay-container'),
|
||||
dialogContainer: by.css('.mat-dialog-container'),
|
||||
snackBarContainer: '.cdk-overlay-pane snack-bar-container.mat-snack-bar-container',
|
||||
snackBar: 'simple-snack-bar',
|
||||
snackBarAction: 'button.mat-simple-snackbar-action'
|
||||
};
|
||||
|
||||
public app: ElementFinder = element(this.locators.app);
|
||||
public layout: ElementFinder = element(this.locators.layout);
|
||||
public overlay: ElementFinder = element(this.locators.overlay);
|
||||
snackBar: ElementFinder = browser.$(this.locators.snackBar);
|
||||
dialogContainer: ElementFinder = element(this.locators.dialogContainer);
|
||||
snackBarContainer: ElementFinder = browser.$(this.locators.snackBarContainer);
|
||||
snackBarAction: ElementFinder = browser.$(this.locators.snackBarAction);
|
||||
|
||||
constructor(public url: string = '') {}
|
||||
|
||||
get title(): promise.Promise<string> {
|
||||
return browser.getTitle();
|
||||
}
|
||||
|
||||
load(relativeUrl: string = ''): promise.Promise<void> {
|
||||
const hash = Page.USE_HASH_STRATEGY ? '/#' : '';
|
||||
const path = `${hash}${this.url}${relativeUrl}`;
|
||||
|
||||
return browser.get(path);
|
||||
}
|
||||
|
||||
waitForApp() {
|
||||
return browser.wait(EC.presenceOf(this.layout), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
waitForSnackBarToAppear() {
|
||||
return browser.wait(EC.visibilityOf(this.snackBarContainer), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
waitForSnackBarToClose() {
|
||||
return browser.wait(EC.not(EC.visibilityOf(this.snackBarContainer)), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
waitForDialog() {
|
||||
return browser.wait(EC.visibilityOf(this.dialogContainer), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
waitForDialogToClose() {
|
||||
return browser.wait(EC.not(EC.visibilityOf(this.dialogContainer)), BROWSER_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
refresh(): promise.Promise<void> {
|
||||
return browser.refresh();
|
||||
}
|
||||
|
||||
getDialogActionByLabel(label) {
|
||||
return element(by.cssContainingText('.mat-button-wrapper', label));
|
||||
}
|
||||
|
||||
isSnackBarDisplayed(): promise.Promise<boolean> {
|
||||
return this.snackBar.isDisplayed();
|
||||
}
|
||||
|
||||
getSnackBarMessage(): promise.Promise<string> {
|
||||
return this.waitForSnackBarToAppear()
|
||||
.then(() => this.snackBar.getAttribute('innerText'));
|
||||
}
|
||||
|
||||
getSnackBarAction() {
|
||||
return this.waitForSnackBarToAppear()
|
||||
.then(() => this.snackBarAction);
|
||||
}
|
||||
|
||||
clickSnackBarAction() {
|
||||
return browser.executeScript(function (elem) {
|
||||
elem.click();
|
||||
}, this.snackBarAction);
|
||||
}
|
||||
}
|
28
e2e/pages/pages.ts
Executable file
28
e2e/pages/pages.ts
Executable file
@ -0,0 +1,28 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from './browsing-page';
|
||||
export * from './login-page';
|
||||
export * from './logout-page';
|
278
e2e/suites/actions/create-folder.test.ts
Executable file
278
e2e/suites/actions/create-folder.test.ts
Executable file
@ -0,0 +1,278 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
|
||||
import { SIDEBAR_LABELS, SITE_VISIBILITY, SITE_ROLES } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Create folder', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
const folderName1 = `folder-${Utils.random()}`;
|
||||
const folderName2 = `folder-${Utils.random()}`;
|
||||
const folderDescription = 'description of my folder';
|
||||
const duplicateFolderName = `folder-${Utils.random()}`;
|
||||
const nameWithSpaces = ` folder-${Utils.random()} `;
|
||||
|
||||
const siteName = `site-private-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const personalFilesPage = new BrowsingPage();
|
||||
const createDialog = new CreateOrEditFolderDialog();
|
||||
const { dataTable } = personalFilesPage;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PRIVATE))
|
||||
.then(() => apis.admin.nodes.createFolders([ folderName1 ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.user.nodes.createFolders([ duplicateFolderName ], parent))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise
|
||||
.all([
|
||||
apis.admin.sites.deleteSite(siteName),
|
||||
apis.user.nodes.deleteNodes([ parent ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('option is enabled when having enough permissions', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openNewMenu())
|
||||
.then(menu => {
|
||||
const isEnabled = menu.getItemByLabel('Create folder').isEnabled();
|
||||
expect(isEnabled).toBe(true, 'Create folder is not enabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('creates new folder with name', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName(folderName1))
|
||||
.then(() => createDialog.clickCreate())
|
||||
.then(() => createDialog.waitForDialogToClose())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
const isPresent = dataTable.getRowName(folderName1).isPresent();
|
||||
expect(isPresent).toBe(true, 'Folder not displayed in list view');
|
||||
});
|
||||
});
|
||||
|
||||
it('creates new folder with name and description', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName(folderName2))
|
||||
.then(() => createDialog.enterDescription(folderDescription))
|
||||
.then(() => createDialog.clickCreate())
|
||||
.then(() => createDialog.waitForDialogToClose())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(dataTable.getRowName(folderName2).isPresent()).toBe(true, 'Folder not displayed'))
|
||||
.then(() => apis.user.nodes.getNodeDescription(folderName2, parent))
|
||||
.then(desc => expect(desc).toEqual(folderDescription));
|
||||
});
|
||||
|
||||
it('enabled option tooltip', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openNewMenu())
|
||||
.then(menu => browser.actions().mouseMove(menu.getItemByLabel('Create folder')).perform()
|
||||
.then(() => menu))
|
||||
.then(menu => {
|
||||
expect(menu.getItemTooltip('Create folder')).toContain('Create new folder');
|
||||
});
|
||||
});
|
||||
|
||||
it('option is disabled when not enough permissions', () => {
|
||||
const fileLibrariesPage = new BrowsingPage();
|
||||
|
||||
fileLibrariesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(siteName))
|
||||
.then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(folderName1))
|
||||
.then(() => fileLibrariesPage.sidenav.openNewMenu())
|
||||
.then(menu => {
|
||||
const isEnabled = menu.getItemByLabel('Create folder').isEnabled();
|
||||
expect(isEnabled).toBe(false, 'Create folder is not disabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('disabled option tooltip', () => {
|
||||
const fileLibrariesPage = new BrowsingPage();
|
||||
|
||||
fileLibrariesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(siteName))
|
||||
.then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(folderName1))
|
||||
.then(() => fileLibrariesPage.sidenav.openNewMenu())
|
||||
.then(menu => browser.actions().mouseMove(menu.getItemByLabel('Create folder')).perform()
|
||||
.then(() => menu))
|
||||
.then(menu => {
|
||||
const tooltip = menu.getItemTooltip('Create folder');
|
||||
expect(tooltip).toContain(`You can't create a folder here`);
|
||||
});
|
||||
});
|
||||
|
||||
it('dialog UI elements', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => {
|
||||
const dialogTitle = createDialog.getTitle();
|
||||
const isFolderNameDisplayed = createDialog.nameInput.isDisplayed();
|
||||
const isDescriptionDisplayed = createDialog.descriptionTextArea.isDisplayed();
|
||||
const isCreateEnabled = createDialog.createButton.isEnabled();
|
||||
const isCancelEnabled = createDialog.cancelButton.isEnabled();
|
||||
|
||||
expect(dialogTitle).toMatch('Create new folder');
|
||||
expect(isFolderNameDisplayed).toBe(true, 'Name input is not displayed');
|
||||
expect(isDescriptionDisplayed).toBe(true, 'Description field is not displayed');
|
||||
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
|
||||
expect(isCancelEnabled).toBe(true, 'Cancel button is not enabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('with empty folder name', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.deleteNameWithBackspace())
|
||||
.then(() => {
|
||||
const isCreateEnabled = createDialog.createButton.isEnabled();
|
||||
const validationMessage = createDialog.getValidationMessage();
|
||||
|
||||
expect(isCreateEnabled).toBe(false, 'Create button is enabled');
|
||||
expect(validationMessage).toMatch('Folder name is required');
|
||||
});
|
||||
});
|
||||
|
||||
it('with folder name ending with a dot "."', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName('folder-name.'))
|
||||
.then(() => {
|
||||
const isCreateEnabled = createDialog.createButton.isEnabled();
|
||||
const validationMessage = createDialog.getValidationMessage();
|
||||
|
||||
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
|
||||
expect(validationMessage).toMatch(`Folder name can't end with a period .`);
|
||||
});
|
||||
});
|
||||
|
||||
it('with folder name containing special characters', () => {
|
||||
const namesWithSpecialChars = [ 'a*a', 'a"a', 'a<a', 'a>a', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ];
|
||||
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => namesWithSpecialChars.forEach(name => {
|
||||
createDialog.enterName(name);
|
||||
|
||||
const isCreateEnabled = createDialog.createButton.isEnabled();
|
||||
const validationMessage = createDialog.getValidationMessage();
|
||||
|
||||
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
|
||||
expect(validationMessage).toContain(`Folder name can't contain these characters`);
|
||||
}));
|
||||
});
|
||||
|
||||
it('with folder name containing only spaces', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName(' '))
|
||||
.then(() => {
|
||||
const isCreateEnabled = createDialog.createButton.isEnabled();
|
||||
const validationMessage = createDialog.getValidationMessage();
|
||||
|
||||
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
|
||||
expect(validationMessage).toMatch(`Folder name can't contain only spaces`);
|
||||
});
|
||||
});
|
||||
|
||||
it('cancel folder creation', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName('test'))
|
||||
.then(() => createDialog.enterDescription('test description'))
|
||||
.then(() => createDialog.clickCancel())
|
||||
.then(() => {
|
||||
expect(createDialog.component.isPresent()).not.toBe(true, 'dialog is not closed');
|
||||
});
|
||||
});
|
||||
|
||||
it('duplicate folder name', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName(duplicateFolderName))
|
||||
.then(() => createDialog.clickCreate())
|
||||
.then(() => personalFilesPage.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toEqual(`There's already a folder with this name. Try a different name.`);
|
||||
expect(createDialog.component.isPresent()).toBe(true, 'dialog is not present');
|
||||
});
|
||||
});
|
||||
|
||||
it('trim ending spaces from folder name', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(parent)
|
||||
.then(() => personalFilesPage.sidenav.openCreateDialog())
|
||||
.then(() => createDialog.waitForDialogToOpen())
|
||||
.then(() => createDialog.enterName(nameWithSpaces))
|
||||
.then(() => createDialog.clickCreate())
|
||||
.then(() => createDialog.waitForDialogToClose())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
const isPresent = dataTable.getRowName(nameWithSpaces.trim()).isPresent();
|
||||
expect(isPresent).toBe(true, 'Folder not displayed in list view');
|
||||
});
|
||||
});
|
||||
});
|
504
e2e/suites/actions/delete.test.ts
Executable file
504
e2e/suites/actions/delete.test.ts
Executable file
@ -0,0 +1,504 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Delete content', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, toolbar } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
apis.admin.trashcan.emptyTrash().then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on Personal Files', () => {
|
||||
const file1 = `file1-${Utils.random()}.txt`; let file1Id;
|
||||
const file2 = `file2-${Utils.random()}.txt`; let file2Id;
|
||||
const file3 = `file3-${Utils.random()}.txt`;
|
||||
const file4 = `file4-${Utils.random()}.txt`; let file4Id;
|
||||
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
|
||||
const folder2 = `folder2-${Utils.random()}`; let folder2Id;
|
||||
const fileLocked1 = `fileLocked-${Utils.random()}.txt`; let fileLocked1Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(file1).then(resp => file1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(file2).then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file3, folder1Id))
|
||||
.then(() => apis.user.nodes.createFile(file4, folder2Id).then(resp => file4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.lockFile(file4Id))
|
||||
|
||||
.then(() => apis.user.nodes.createFile(fileLocked1).then(resp => fileLocked1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.lockFile(fileLocked1Id))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.unlockFile(file4Id)
|
||||
.then(() => apis.user.nodes.unlockFile(fileLocked1Id))
|
||||
.then(() => apis.user.nodes.deleteNodesById([file1Id, file2Id, folder1Id, folder2Id, fileLocked1Id]))
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('delete a file and check notification', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(file1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`${file1} deleted`);
|
||||
expect(dataTable.getRowName(file1).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
items--;
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => expect(dataTable.getRowName(file1).isPresent()).toBe(true, 'Item is not in trash'))
|
||||
|
||||
.then(() => apis.user.trashcan.restore(file1Id));
|
||||
});
|
||||
|
||||
it('delete multiple files and check notification', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`Deleted 2 items`);
|
||||
expect(dataTable.getRowName(file1).isPresent()).toBe(false, `${file1} was not removed from list`);
|
||||
expect(dataTable.getRowName(file2).isPresent()).toBe(false, `${file2} was not removed from list`);
|
||||
items = items - 2;
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(file1).isPresent()).toBe(true, `${file1} is not in trash`);
|
||||
expect(dataTable.getRowName(file2).isPresent()).toBe(true, `${file2} is not in trash`);
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(file1Id))
|
||||
.then(() => apis.user.trashcan.restore(file2Id));
|
||||
});
|
||||
|
||||
it('delete a folder with content', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(folder1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(folder1).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
items--;
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(folder1).isPresent()).toBe(true, 'Item is not in trash');
|
||||
expect(dataTable.getRowName(file3).isPresent()).toBe(false, 'Item is in trash');
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(folder1Id));
|
||||
});
|
||||
|
||||
it('delete a folder containing locked files', () => {
|
||||
dataTable.clickOnItemName(folder2)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`${folder2} couldn't be deleted`);
|
||||
expect(dataTable.getRowName(folder2).isPresent()).toBe(true, 'Item was removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(folder2).isPresent()).toBe(false, 'Item is in trash');
|
||||
expect(dataTable.getRowName(file4).isPresent()).toBe(false, 'Item is in trash');
|
||||
});
|
||||
});
|
||||
|
||||
it('notification on multiple items deletion - some items fail to delete', () => {
|
||||
dataTable.selectMultipleItems([file1, folder2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => expect(message).toContain(`Deleted 1 item, 1 couldn't be deleted`))
|
||||
|
||||
.then(() => apis.user.trashcan.restore(file1Id));
|
||||
});
|
||||
|
||||
// TODO: needs to operate on two folders containing locked items
|
||||
xit('Notification on multiple items deletion - all items fail to delete', () => {
|
||||
dataTable.selectMultipleItems([fileLocked1, folder2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => expect(message).toEqual(`2 items couldn't be deleted`));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Shared Files', () => {
|
||||
const sharedFile1 = `sharedFile1-${Utils.random()}.txt`; let sharedFile1Id;
|
||||
const sharedFile2 = `sharedFile2-${Utils.random()}.txt`; let sharedFile2Id;
|
||||
const sharedFile3 = `sharedFile3-${Utils.random()}.txt`; let sharedFile3Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(sharedFile1).then(resp => sharedFile1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(sharedFile2).then(resp => sharedFile2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(sharedFile3).then(resp => sharedFile3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.shared.shareFilesByIds([sharedFile1Id, sharedFile2Id, sharedFile3Id]))
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 3 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.deleteNodesById([sharedFile1Id, sharedFile2Id, sharedFile3Id])
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('delete a file and check notification', () => {
|
||||
dataTable.clickOnItemName(sharedFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`${sharedFile1} deleted`);
|
||||
expect(dataTable.getRowName(sharedFile1).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => expect(dataTable.getRowName(sharedFile1).isPresent()).toBe(true, 'Item is not in trash'))
|
||||
|
||||
.then(() => apis.user.trashcan.restore(sharedFile1Id));
|
||||
});
|
||||
|
||||
it('delete multiple files and check notification', () => {
|
||||
dataTable.selectMultipleItems([sharedFile2, sharedFile3])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`Deleted 2 items`);
|
||||
expect(dataTable.getRowName(sharedFile2).isPresent()).toBe(false, `${sharedFile2} was not removed from list`);
|
||||
expect(dataTable.getRowName(sharedFile3).isPresent()).toBe(false, `${sharedFile3} was not removed from list`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(sharedFile2).isPresent()).toBe(true, `${sharedFile2} is not in trash`);
|
||||
expect(dataTable.getRowName(sharedFile3).isPresent()).toBe(true, `${sharedFile3} is not in trash`);
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(sharedFile2Id))
|
||||
.then(() => apis.user.trashcan.restore(sharedFile3Id));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Favorites', () => {
|
||||
const favoriteFile1 = `favFile1-${Utils.random()}.txt`; let favoriteFile1Id;
|
||||
const favoriteFile2 = `favFile2-${Utils.random()}.txt`; let favoriteFile2Id;
|
||||
const favoriteFile3 = `favFile3-${Utils.random()}.txt`;
|
||||
const favoriteFile4 = `favFile4-${Utils.random()}.txt`; let favoriteFile4Id;
|
||||
const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id;
|
||||
const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id;
|
||||
const favoriteFileLocked1 = `favFileLocked-${Utils.random()}.txt`; let favoriteFileLocked1Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(favoriteFile1).then(resp => favoriteFile1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(favoriteFile2).then(resp => favoriteFile2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(favoriteFolder1).then(resp => favoriteFolder1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(favoriteFolder2).then(resp => favoriteFolder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(favoriteFile3, favoriteFolder1Id))
|
||||
.then(() => apis.user.nodes.createFile(favoriteFile4, favoriteFolder2Id).then(resp => favoriteFile4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.lockFile(favoriteFile4Id))
|
||||
|
||||
.then(() => apis.user.nodes.createFile(favoriteFileLocked1).then(resp => favoriteFileLocked1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.lockFile(favoriteFileLocked1Id))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('file', [favoriteFile1Id, favoriteFile2Id, favoriteFileLocked1Id]))
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('folder', [favoriteFolder1Id, favoriteFolder2Id]))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 5 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.unlockFile(favoriteFile4Id)
|
||||
.then(() => apis.user.nodes.unlockFile(favoriteFileLocked1Id))
|
||||
.then(() => apis.user.nodes.deleteNodesById([
|
||||
favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id, favoriteFileLocked1Id
|
||||
]))
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('delete a file and check notification', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(favoriteFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`${favoriteFile1} deleted`);
|
||||
expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
items--;
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, 'Item is not in trash'))
|
||||
|
||||
.then(() => apis.user.trashcan.restore(favoriteFile1Id));
|
||||
});
|
||||
|
||||
it('delete multiple files and check notification', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.selectMultipleItems([favoriteFile1, favoriteFile2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`Deleted 2 items`);
|
||||
expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(false, `${favoriteFile1} was not removed from list`);
|
||||
expect(dataTable.getRowName(favoriteFile2).isPresent()).toBe(false, `${favoriteFile2} was not removed from list`);
|
||||
items = items - 2;
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, `${favoriteFile1} is not in trash`);
|
||||
expect(dataTable.getRowName(favoriteFile2).isPresent()).toBe(true, `${favoriteFile2} is not in trash`);
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(favoriteFile1Id))
|
||||
.then(() => apis.user.trashcan.restore(favoriteFile2Id));
|
||||
});
|
||||
|
||||
it('delete a folder with content', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
dataTable.clickOnItemName(favoriteFolder1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFolder1).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
items--;
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFolder1).isPresent()).toBe(true, 'Item is not in trash');
|
||||
expect(dataTable.getRowName(favoriteFile3).isPresent()).toBe(false, 'Item is in trash');
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(favoriteFolder1Id));
|
||||
});
|
||||
|
||||
it('delete a folder containing locked files', () => {
|
||||
dataTable.clickOnItemName(favoriteFolder2)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`${favoriteFolder2} couldn't be deleted`);
|
||||
expect(dataTable.getRowName(favoriteFolder2).isPresent()).toBe(true, 'Item was removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFolder2).isPresent()).toBe(false, 'Item is in trash');
|
||||
expect(dataTable.getRowName(favoriteFile4).isPresent()).toBe(false, 'Item is in trash');
|
||||
});
|
||||
});
|
||||
|
||||
it('notification on multiple items deletion - some items fail to delete', () => {
|
||||
dataTable.selectMultipleItems([favoriteFile1, favoriteFolder2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`Deleted 1 item, 1 couldn't be deleted`);
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(favoriteFile1Id));
|
||||
});
|
||||
|
||||
it('Notification on multiple items deletion - all items fail to delete', () => {
|
||||
dataTable.selectMultipleItems([favoriteFileLocked1, favoriteFolder2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toEqual(`2 items couldn't be deleted`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Recent Files', () => {
|
||||
const recentFile1 = `recentFile1-${Utils.random()}.txt`; let recentFile1Id;
|
||||
const recentFile2 = `recentFile2-${Utils.random()}.txt`; let recentFile2Id;
|
||||
const recentFile3 = `recentFile3-${Utils.random()}.txt`; let recentFile3Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(recentFile1).then(resp => recentFile1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(recentFile2).then(resp => recentFile2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(recentFile3).then(resp => recentFile3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.search.waitForApi(username, { expect: 3 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
|
||||
.then((): any => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.isEmptyList())
|
||||
.then(empty => {
|
||||
if (empty) {
|
||||
browser.sleep(6000).then(() => page.refresh());
|
||||
}
|
||||
})
|
||||
)
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.deleteNodesById([recentFile1Id, recentFile2Id, recentFile3Id])
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('delete a file and check notification', () => {
|
||||
dataTable.clickOnItemName(recentFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`${recentFile1} deleted`);
|
||||
expect(dataTable.getRowName(recentFile1).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => expect(dataTable.getRowName(recentFile1).isPresent()).toBe(true, 'Item is not in trash'))
|
||||
|
||||
.then(() => apis.user.trashcan.restore(recentFile1Id));
|
||||
});
|
||||
|
||||
xit('delete multiple files and check notification', () => {
|
||||
dataTable.selectMultipleItems([recentFile2, recentFile3])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`Deleted 2 items`);
|
||||
expect(dataTable.getRowName(recentFile2).isPresent()).toBe(false, `${recentFile2} was not removed from list`);
|
||||
expect(dataTable.getRowName(recentFile3).isPresent()).toBe(false, `${recentFile3} was not removed from list`);
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(recentFile2).isPresent()).toBe(true, `${recentFile2} is not in trash`);
|
||||
expect(dataTable.getRowName(recentFile3).isPresent()).toBe(true, `${recentFile3} is not in trash`);
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(recentFile2Id))
|
||||
.then(() => apis.user.trashcan.restore(recentFile3Id));
|
||||
});
|
||||
});
|
||||
});
|
187
e2e/suites/actions/edit-folder.test.ts
Executable file
187
e2e/suites/actions/edit-folder.test.ts
Executable file
@ -0,0 +1,187 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { protractor, browser } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SIDEBAR_LABELS, SITE_VISIBILITY, SITE_ROLES } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Edit folder', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
const folderName = `folder-${Utils.random()}`;
|
||||
const folderDescription = 'my folder description';
|
||||
|
||||
const folderNameToEdit = `folder-${Utils.random()}`;
|
||||
const duplicateFolderName = `folder-${Utils.random()}`;
|
||||
|
||||
const folderNameEdited = `folder-${Utils.random()}`;
|
||||
const folderDescriptionEdited = 'description edited';
|
||||
|
||||
const siteName = `site-private-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const personalFilesPage = new BrowsingPage();
|
||||
const editDialog = new CreateOrEditFolderDialog();
|
||||
const { dataTable } = personalFilesPage;
|
||||
const editButton = personalFilesPage.toolbar.actions.getButtonByTitleAttribute('Edit');
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PRIVATE))
|
||||
.then(() => apis.admin.nodes.createFolders([ folderName ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER))
|
||||
|
||||
.then(() => apis.user.nodes.createFolder( parent ))
|
||||
.then(resp => apis.user.nodes.createFolder( folderName, resp.data.entry.id, '', folderDescription ))
|
||||
.then(() => apis.user.nodes.createFolders([ folderNameToEdit, duplicateFolderName ], parent))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.doubleClickOnItemName(parent))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise
|
||||
.all([
|
||||
apis.admin.sites.deleteSite(siteName),
|
||||
apis.user.nodes.deleteNodes([ parent ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('dialog UI defaults', () => {
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => {
|
||||
expect(editDialog.getTitle()).toEqual('Edit folder');
|
||||
expect(editDialog.nameInput.getAttribute('value')).toBe(folderName);
|
||||
expect(editDialog.descriptionTextArea.getAttribute('value')).toBe(folderDescription);
|
||||
expect(editDialog.updateButton.isEnabled()).toBe(true, 'upload button is not enabled');
|
||||
expect(editDialog.cancelButton.isEnabled()).toBe(true, 'cancel button is not enabled');
|
||||
});
|
||||
});
|
||||
|
||||
it('properties are modified when pressing OK', () => {
|
||||
dataTable.clickOnItemName(folderNameToEdit)
|
||||
.then(() => editButton.click())
|
||||
.then(() => editDialog.waitForDialogToOpen())
|
||||
.then(() => editDialog.enterDescription(folderDescriptionEdited))
|
||||
.then(() => editDialog.enterName(folderNameEdited))
|
||||
.then(() => editDialog.clickUpdate())
|
||||
.then(() => editDialog.waitForDialogToClose())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(dataTable.getRowName(folderNameEdited).isPresent()).toBe(true, 'Folder not displayed'))
|
||||
.then(() => apis.user.nodes.getNodeDescription(folderNameEdited, parent))
|
||||
.then(desc => expect(desc).toEqual(folderDescriptionEdited));
|
||||
});
|
||||
|
||||
it('with empty folder name', () => {
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => editDialog.deleteNameWithBackspace())
|
||||
.then(() => {
|
||||
expect(editDialog.updateButton.isEnabled()).toBe(false, 'upload button is not enabled');
|
||||
expect(editDialog.getValidationMessage()).toMatch('Folder name is required');
|
||||
});
|
||||
});
|
||||
|
||||
it('with name with special characters', () => {
|
||||
const namesWithSpecialChars = [ 'a*a', 'a"a', 'a<a', 'a>a', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ];
|
||||
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => namesWithSpecialChars.forEach(name => {
|
||||
editDialog.enterName(name);
|
||||
|
||||
expect(editDialog.updateButton.isEnabled()).toBe(false, 'upload button is not disabled');
|
||||
expect(editDialog.getValidationMessage()).toContain(`Folder name can't contain these characters`);
|
||||
}));
|
||||
});
|
||||
|
||||
it('with name ending with a dot', () => {
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => editDialog.nameInput.sendKeys('.'))
|
||||
.then(() => {
|
||||
expect(editDialog.updateButton.isEnabled()).toBe(false, 'upload button is not enabled');
|
||||
expect(editDialog.getValidationMessage()).toMatch(`Folder name can't end with a period .`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Cancel button', () => {
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => editDialog.clickCancel())
|
||||
.then(() => {
|
||||
expect(editDialog.component.isPresent()).not.toBe(true, 'dialog is not closed');
|
||||
});
|
||||
});
|
||||
|
||||
it('with duplicate folder name', () => {
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => editDialog.enterName(duplicateFolderName))
|
||||
.then(() => editDialog.clickUpdate())
|
||||
.then(() => personalFilesPage.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toEqual(`There's already a folder with this name. Try a different name.`);
|
||||
expect(editDialog.component.isPresent()).toBe(true, 'dialog is not present');
|
||||
});
|
||||
});
|
||||
|
||||
it('trim ending spaces', () => {
|
||||
dataTable.clickOnItemName(folderName)
|
||||
.then(() => editButton.click())
|
||||
.then(() => editDialog.nameInput.sendKeys(' '))
|
||||
.then(() => editDialog.clickUpdate())
|
||||
.then(() => editDialog.waitForDialogToClose())
|
||||
.then(() => {
|
||||
expect(personalFilesPage.snackBar.isPresent()).not.toBe(true, 'notification appears');
|
||||
expect(dataTable.getRowName(folderName).isPresent()).toBe(true, 'Folder not displayed in list view');
|
||||
});
|
||||
});
|
||||
});
|
419
e2e/suites/actions/mark-favorite.test.ts
Normal file
419
e2e/suites/actions/mark-favorite.test.ts
Normal file
@ -0,0 +1,419 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { browser } from 'protractor';
|
||||
|
||||
describe('Mark items as favorites', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const file1NotFav = `file-${Utils.random()}.txt`;
|
||||
const file2NotFav = `file-${Utils.random()}.txt`;
|
||||
const file3Fav = `file-${Utils.random()}.txt`;
|
||||
const file4Fav = `file-${Utils.random()}.txt`;
|
||||
const folder1 = `folder-${Utils.random()}`;
|
||||
|
||||
let file1Id, file2Id, file3Id, file4Id, folder1Id;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, toolbar } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFile( file1NotFav ).then(resp => file1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile( file2NotFav ).then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile( file3Fav ).then(resp => file3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile( file4Fav ).then(resp => file4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder( folder1 ).then(resp => folder1Id = resp.data.entry.id))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file4Id))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodesById([ file1Id, file2Id, file3Id, file4Id, folder1Id ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on Personal Files', () => {
|
||||
beforeAll(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
// browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done);
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
it('Favorite action has empty star icon for an item not marked as favorite', () => {
|
||||
dataTable.clickOnItemName(file1NotFav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star_border'));
|
||||
});
|
||||
|
||||
it('Favorite action has empty star icon for multiple selection of items when some are not favorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file3Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star_border'));
|
||||
});
|
||||
|
||||
it('Favorite action has full star icon for items marked as favorite', () => {
|
||||
dataTable.clickOnItemName(file3Fav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star'));
|
||||
});
|
||||
|
||||
it('favorite a file', () => {
|
||||
dataTable.clickOnItemName(file1NotFav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file1Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(true, `${file1NotFav} not marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id));
|
||||
});
|
||||
|
||||
it('favorite a folder', () => {
|
||||
dataTable.clickOnItemName(folder1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => apis.user.favorites.isFavorite(folder1Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(true, `${folder1} not marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(folder1Id));
|
||||
});
|
||||
|
||||
it('unfavorite an item', () => {
|
||||
dataTable.clickOnItemName(file3Fav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 1 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file3Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(false, `${file3Fav} is marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id));
|
||||
});
|
||||
|
||||
it('favorite multiple items - all unfavorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file2NotFav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 4 }))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file1Id),
|
||||
apis.user.favorites.isFavorite(file2Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(true, 'item not marked as favorite');
|
||||
expect(resp[1]).toBe(true, 'item not marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id))
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file2Id));
|
||||
});
|
||||
|
||||
it('favorite multiple items - some favorite and some unfavorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file3Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file1Id),
|
||||
apis.user.favorites.isFavorite(file3Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(true, 'item not marked as favorite');
|
||||
expect(resp[1]).toBe(true, 'item not marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id));
|
||||
});
|
||||
|
||||
it('unfavorite multiple items', () => {
|
||||
dataTable.selectMultipleItems([ file3Fav, file4Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => browser.sleep(2000))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file3Id),
|
||||
apis.user.favorites.isFavorite(file4Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(false, 'item marked as favorite');
|
||||
expect(resp[1]).toBe(false, 'item marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file4Id));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Recent Files', () => {
|
||||
beforeAll(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
// browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done);
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
it('favorite a file', () => {
|
||||
dataTable.clickOnItemName(file1NotFav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file1Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(true, `${file1NotFav} not marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id));
|
||||
});
|
||||
|
||||
it('unfavorite an item', () => {
|
||||
dataTable.clickOnItemName(file3Fav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 1 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file3Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(false, `${file3Fav} is marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id));
|
||||
});
|
||||
|
||||
it('favorite multiple items - all unfavorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file2NotFav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 4 }))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file1Id),
|
||||
apis.user.favorites.isFavorite(file2Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(true, 'item not marked as favorite');
|
||||
expect(resp[1]).toBe(true, 'item not marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id))
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file2Id));
|
||||
});
|
||||
|
||||
it('favorite multiple items - some favorite and some unfavorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file3Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file1Id),
|
||||
apis.user.favorites.isFavorite(file3Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(true, 'item not marked as favorite');
|
||||
expect(resp[1]).toBe(true, 'item not marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id));
|
||||
});
|
||||
|
||||
it('unfavorite multiple items', () => {
|
||||
dataTable.selectMultipleItems([ file3Fav, file4Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => browser.sleep(2000))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file3Id),
|
||||
apis.user.favorites.isFavorite(file4Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(false, 'item marked as favorite');
|
||||
expect(resp[1]).toBe(false, 'item marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file4Id));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Shared Files', () => {
|
||||
beforeAll(done => {
|
||||
apis.user.shared.shareFilesByIds([ file1Id, file2Id, file3Id, file4Id ])
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 4 }))
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
// browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done);
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
it('favorite a file', () => {
|
||||
dataTable.clickOnItemName(file1NotFav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file1Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(true, `${file1NotFav} not marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id));
|
||||
});
|
||||
|
||||
it('unfavorite an item', () => {
|
||||
dataTable.clickOnItemName(file3Fav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 1 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file3Id))
|
||||
.then(isFavorite => expect(isFavorite).toBe(false, `${file3Fav} is marked as favorite`))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id));
|
||||
});
|
||||
|
||||
it('favorite multiple items - all unfavorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file2NotFav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 4 }))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file1Id),
|
||||
apis.user.favorites.isFavorite(file2Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(true, 'item not marked as favorite');
|
||||
expect(resp[1]).toBe(true, 'item not marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id))
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file2Id));
|
||||
});
|
||||
|
||||
it('favorite multiple items - some favorite and some unfavorite', () => {
|
||||
dataTable.selectMultipleItems([ file1NotFav, file3Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 3 }))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file1Id),
|
||||
apis.user.favorites.isFavorite(file3Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(true, 'item not marked as favorite');
|
||||
expect(resp[1]).toBe(true, 'item not marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.removeFavoriteById(file1Id));
|
||||
});
|
||||
|
||||
it('unfavorite multiple items', () => {
|
||||
dataTable.selectMultipleItems([ file3Fav, file4Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => browser.sleep(2000))
|
||||
.then(() => Promise.all([
|
||||
apis.user.favorites.isFavorite(file3Id),
|
||||
apis.user.favorites.isFavorite(file4Id)
|
||||
]))
|
||||
.then(resp => {
|
||||
expect(resp[0]).toBe(false, 'item marked as favorite');
|
||||
expect(resp[1]).toBe(false, 'item marked as favorite');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file4Id));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Favorites', () => {
|
||||
beforeAll(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
it('unfavorite an item', () => {
|
||||
dataTable.clickOnItemName(file3Fav)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 1 }))
|
||||
.then(() => apis.user.favorites.isFavorite(file3Id))
|
||||
.then(isFavorite => {
|
||||
expect(isFavorite).toBe(false, 'item is marked as favorite');
|
||||
expect(dataTable.getRowName(file3Fav).isPresent()).toBe(false, 'item still displayed');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id));
|
||||
});
|
||||
|
||||
it('unfavorite multiple items', () => {
|
||||
dataTable.selectMultipleItems([ file3Fav, file4Fav ])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Favorite'))
|
||||
.then(() => browser.sleep(2000))
|
||||
.then(() => apis.user.favorites.isFavorite(file3Id))
|
||||
.then(resp => {
|
||||
expect(resp).toBe(false, 'file3 marked as favorite');
|
||||
expect(dataTable.getRowName(file3Fav).isPresent()).toBe(false, 'file3 still displayed');
|
||||
})
|
||||
.then(() => apis.user.favorites.isFavorite(file4Id))
|
||||
.then(resp => {
|
||||
expect(resp).toBe(false, 'file4 marked as favorite');
|
||||
expect(dataTable.getRowName(file4Fav).isPresent()).toBe(false, 'file4 still displayed');
|
||||
})
|
||||
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file4Id));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
122
e2e/suites/actions/permanently-delete.test.ts
Executable file
122
e2e/suites/actions/permanently-delete.test.ts
Executable file
@ -0,0 +1,122 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Permanently delete from Trash', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const file1 = `file-${Utils.random()}.txt`;
|
||||
const file2 = `file-${Utils.random()}.txt`;
|
||||
let filesIds;
|
||||
|
||||
const folder1 = `folder-${Utils.random()}`;
|
||||
const folder2 = `folder-${Utils.random()}`;
|
||||
let foldersIds;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const trashPage = new BrowsingPage();
|
||||
const { dataTable, toolbar } = trashPage;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFiles([ file1, file2 ]))
|
||||
.then(resp => filesIds = resp.data.list.entries.map(entries => entries.entry.id))
|
||||
.then(() => apis.user.nodes.createFolders([ folder1, folder2 ]))
|
||||
.then(resp => foldersIds = resp.data.list.entries.map(entries => entries.entry.id))
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodesById(filesIds, false))
|
||||
.then(() => apis.user.nodes.deleteNodesById(foldersIds, false))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
trashPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('delete file [C217094] [C217091] [C217092]', () => {
|
||||
dataTable.clickOnItemName(file1)
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Permanently delete').click())
|
||||
.then(() => trashPage.waitForDialog())
|
||||
.then(() => trashPage.getDialogActionByLabel('Delete'))
|
||||
.then((elm) => elm.click())
|
||||
.then(() => trashPage.waitForDialogToClose())
|
||||
.then(() => trashPage.getSnackBarMessage())
|
||||
.then(text => {
|
||||
expect(text).toEqual(`${file1} deleted`);
|
||||
expect(dataTable.getRowName(file1).isPresent()).toBe(false, 'Item was not deleted');
|
||||
});
|
||||
});
|
||||
|
||||
it('delete folder [C217091] [C217092]', () => {
|
||||
dataTable.clickOnItemName(folder1)
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Permanently delete').click())
|
||||
.then(() => trashPage.waitForDialog())
|
||||
.then(() => trashPage.getDialogActionByLabel('Delete'))
|
||||
.then((elm) => elm.click())
|
||||
.then(() => trashPage.waitForDialogToClose())
|
||||
.then(() => trashPage.getSnackBarMessage())
|
||||
.then(text => {
|
||||
expect(text).toEqual(`${folder1} deleted`);
|
||||
expect(dataTable.getRowName(folder1).isPresent()).toBe(false, 'Item was not deleted');
|
||||
});
|
||||
});
|
||||
|
||||
it('delete multiple items [C217093]', () => {
|
||||
dataTable.selectMultipleItems([ file2, folder2 ])
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Permanently delete').click())
|
||||
.then(() => trashPage.waitForDialog())
|
||||
.then(() => trashPage.getDialogActionByLabel('Delete'))
|
||||
.then((elm) => elm.click())
|
||||
.then(() => trashPage.waitForDialogToClose())
|
||||
.then(() => trashPage.getSnackBarMessage())
|
||||
.then(text => {
|
||||
expect(text).toEqual(`2 items deleted`);
|
||||
expect(dataTable.getRowName(file2).isPresent()).toBe(false, 'Item was not deleted');
|
||||
expect(dataTable.getRowName(folder2).isPresent()).toBe(false, 'Item was not deleted');
|
||||
});
|
||||
});
|
||||
});
|
268
e2e/suites/actions/restore.test.ts
Executable file
268
e2e/suites/actions/restore.test.ts
Executable file
@ -0,0 +1,268 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { APP_ROUTES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Restore from Trash', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, toolbar } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('successful restore', () => {
|
||||
const file = `file-${Utils.random()}.txt`; let fileId;
|
||||
const folder = `folder-${Utils.random()}`; let folderId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(file).then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolder(folder).then(resp => folderId = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.deleteNodesById([ fileId, folderId ], false))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
apis.user.trashcan.emptyTrash().then(done);
|
||||
});
|
||||
|
||||
it('restore file', () => {
|
||||
dataTable.clickOnItemName(file)
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => {
|
||||
expect(text).toContain(`${file} restored`);
|
||||
expect(text).toContain(`View`);
|
||||
expect(dataTable.getRowName(file).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES))
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(page.dataTable.getRowName(file).isPresent()).toBe(true, 'Item not displayed in list');
|
||||
})
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodeById(fileId, false));
|
||||
});
|
||||
|
||||
it('restore folder', () => {
|
||||
dataTable.clickOnItemName(folder)
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => {
|
||||
expect(text).toContain(`${folder} restored`);
|
||||
expect(text).toContain(`View`);
|
||||
expect(dataTable.getRowName(folder).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES))
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(page.dataTable.getRowName(folder).isPresent()).toBe(true, 'Item not displayed in list');
|
||||
})
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodeById(folderId, false));
|
||||
});
|
||||
|
||||
it('restore multiple items', () => {
|
||||
dataTable.selectMultipleItems([ file, folder ])
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => {
|
||||
expect(text).toContain(`Restore successful`);
|
||||
expect(text).not.toContain(`View`);
|
||||
expect(dataTable.getRowName(file).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
expect(dataTable.getRowName(folder).isPresent()).toBe(false, 'Item was not removed from list');
|
||||
})
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES))
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(page.dataTable.getRowName(file).isPresent()).toBe(true, 'Item not displayed in list');
|
||||
expect(page.dataTable.getRowName(folder).isPresent()).toBe(true, 'Item not displayed in list');
|
||||
})
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodesById([ fileId, folderId ], false));
|
||||
});
|
||||
|
||||
it('View from notification', () => {
|
||||
dataTable.clickOnItemName(file)
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(page.sidenav.isActiveByLabel('Personal Files')).toBe(true, 'Personal Files sidebar link not active');
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
})
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodeById(fileId, false));
|
||||
});
|
||||
});
|
||||
|
||||
describe('failure to restore', () => {
|
||||
const file1 = `file-${Utils.random()}.txt`; let file1Id1, file1Id2;
|
||||
const file2 = `file-${Utils.random()}.txt`; let file2Id;
|
||||
|
||||
const folder1 = `folder-${Utils.random()}`; let folder1Id;
|
||||
const folder2 = `folder-${Utils.random()}`; let folder2Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(file1, folder1Id).then(resp => file1Id1 = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file1Id1, false))
|
||||
.then(() => apis.user.nodes.createFile(file1, folder1Id).then(resp => file1Id2 = resp.data.entry.id))
|
||||
|
||||
.then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file2, folder2Id).then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file2Id, false))
|
||||
.then(() => apis.user.nodes.deleteNodeById(folder2Id, false))
|
||||
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodeById(file1Id2),
|
||||
apis.user.trashcan.emptyTrash()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Restore a file when another file with same name exists on the restore location', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.clickOnItemName(file1))
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => expect(text).toEqual(`Can't restore, ${file1} already exists`));
|
||||
});
|
||||
|
||||
it('Restore a file when original location no longer exists', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.clickOnItemName(file2))
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => expect(text).toEqual(`Can't restore ${file2}, the original location no longer exists`));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Notification on partial success', () => {
|
||||
const folder1 = `folder1-${Utils.random()}.txt`; let folder1Id;
|
||||
const folder2 = `folder2-${Utils.random()}.txt`; let folder2Id;
|
||||
const file1 = `file-${Utils.random()}.txt`; let file1Id;
|
||||
const file2 = `file-${Utils.random()}.txt`; let file2Id;
|
||||
|
||||
const folder3 = `folder3-${Utils.random()}.txt`; let folder3Id;
|
||||
const folder4 = `folder4-${Utils.random()}.txt`; let folder4Id;
|
||||
const file3 = `file3-${Utils.random()}.txt`; let file3Id;
|
||||
const file4 = `file4-${Utils.random()}.txt`; let file4Id;
|
||||
const file5 = `file5-${Utils.random()}.txt`; let file5Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(file1, folder1Id).then(resp => file1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file2, folder2Id).then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file1Id, false))
|
||||
.then(() => apis.user.nodes.deleteNodeById(folder1Id, false))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file2Id, false))
|
||||
|
||||
.then(() => apis.user.nodes.createFolder(folder3).then(resp => folder3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file3, folder3Id).then(resp => file3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file4, folder3Id).then(resp => file4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(folder4).then(resp => folder4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file5, folder4Id).then(resp => file5Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file3Id, false))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file4Id, false))
|
||||
.then(() => apis.user.nodes.deleteNodeById(folder3Id, false))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file5Id, false))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('one failure', () => {
|
||||
dataTable.selectMultipleItems([ file1, file2 ])
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => expect(text).toEqual(`Can't restore ${file1}, the original location no longer exists`));
|
||||
});
|
||||
|
||||
it('multiple failures', () => {
|
||||
dataTable.selectMultipleItems([ file3, file4, file5 ])
|
||||
.then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click())
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(text => expect(text).toEqual('2 items not restored because of issues with the restore location'));
|
||||
});
|
||||
});
|
||||
});
|
570
e2e/suites/actions/toolbar-multiple-selection.test.ts
Executable file
570
e2e/suites/actions/toolbar-multiple-selection.test.ts
Executable file
@ -0,0 +1,570 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser, protractor } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Toolbar actions - multiple selection : ', () => {
|
||||
const user1 = `user-${Utils.random()}`;
|
||||
const user2 = `user-${Utils.random()}`;
|
||||
|
||||
const file1 = `file-${Utils.random()}.txt`;
|
||||
let file1Id;
|
||||
const file2 = `file-${Utils.random()}.txt`;
|
||||
let file2Id;
|
||||
|
||||
const folder1 = `folder-${Utils.random()}`;
|
||||
let folder1Id;
|
||||
const folder2 = `folder-${Utils.random()}`;
|
||||
let folder2Id;
|
||||
|
||||
const fileForDelete1 = `file-${Utils.random()}.txt`; let fileForDelete1Id;
|
||||
const fileForDelete2 = `file-${Utils.random()}.txt`; let fileForDelete2Id;
|
||||
const folderForDelete1 = `folder-${Utils.random()}`; let folderForDelete1Id;
|
||||
const folderForDelete2 = `folder-${Utils.random()}`; let folderForDelete2Id;
|
||||
|
||||
const siteName = `site-private-${Utils.random()}`;
|
||||
const file1Admin = `file-${Utils.random()}.txt`;
|
||||
const file2Admin = `file-${Utils.random()}.txt`;
|
||||
const folder1Admin = `folder-${Utils.random()}`;
|
||||
const folder2Admin = `folder-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(user1, user1)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable } = page;
|
||||
const { toolbar } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(user1)
|
||||
.then(() => apis.user.nodes.createFiles([ file1 ]).then(resp => file1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFiles([ file2 ]).then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolders([ folder1 ]).then(resp => folder1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolders([ folder2 ]).then(resp => folder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFiles([ fileForDelete1 ]).then(resp => fileForDelete1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFiles([ fileForDelete2 ]).then(resp => fileForDelete2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolders([ folderForDelete1 ]).then(resp => folderForDelete1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolders([ folderForDelete2 ]).then(resp => folderForDelete2Id = resp.data.entry.id))
|
||||
|
||||
.then(() => apis.user.shared.shareFilesByIds([ file1Id, file2Id ]))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('file', [ file1Id, file2Id ]))
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('folder', [ folder1Id, folder2Id ]))
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodesById([
|
||||
fileForDelete1Id, fileForDelete2Id, folderForDelete1Id, folderForDelete2Id
|
||||
], false))
|
||||
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodesById([ file1Id, file2Id, folder1Id, folder2Id ]),
|
||||
apis.user.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('Personal Files', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user1).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('unselect selected items - single click', () => {
|
||||
dataTable.selectMultipleItems([ file1, file2, folder1, folder2 ])
|
||||
.then(() => expect(dataTable.countSelectedRows()).toEqual(4, 'incorrect selected rows number'))
|
||||
.then(() => dataTable.clickOnItemName(file1))
|
||||
.then(() => expect(dataTable.countSelectedRows()).toEqual(1, 'incorrect selected rows number'))
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('unselect selected items - CMD+click', () => {
|
||||
dataTable.selectMultipleItems([ file1, file2, folder1, folder2 ])
|
||||
.then(() => expect(dataTable.countSelectedRows()).toEqual(4, 'incorrect selected rows number'))
|
||||
.then(() => browser.actions().sendKeys(protractor.Key.COMMAND).perform())
|
||||
.then(() => dataTable.clickOnItemName(file1))
|
||||
.then(() => dataTable.clickOnItemName(file2))
|
||||
.then(() => browser.actions().sendKeys(protractor.Key.NULL).perform())
|
||||
.then(() => expect(dataTable.countSelectedRows()).toEqual(2, 'incorrect selected rows number'))
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1, folder2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('should not display View action when multiple entries selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
|
||||
it('should display View action when one file is selected', async () => {
|
||||
await dataTable.selectMultipleItems([file1]);
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'Action is not displayed');
|
||||
});
|
||||
|
||||
it('should not display View action when only folders selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('should display Download action for selected items', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Action is not displayed');
|
||||
});
|
||||
|
||||
it('should not display Download action for empty selection', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
await dataTable.clearSelection();
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('should display Edit action when single folder selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1]);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Action is not displayed');
|
||||
});
|
||||
|
||||
it('should not display Edit action when multiple folders selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('should not display Edit action if no folders selected', async () => {
|
||||
await dataTable.selectMultipleItems([file1, file2]);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2, folder1, folder2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Libraries', () => {
|
||||
beforeAll(done => {
|
||||
apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)
|
||||
.then(() => apis.admin.people.createUser(user2))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, user1, SITE_ROLES.SITE_MANAGER))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, user2, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.admin.nodes.createFiles([ file1Admin, file2Admin ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(() => apis.admin.nodes.createFolders([ folder1Admin, folder2Admin ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.doubleClickOnItemName(siteName))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
apis.admin.sites.deleteSite(siteName).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('user is Manager', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user1).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
|
||||
describe('user is Consumer', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user2).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Shared Files', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user1).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
|
||||
describe('Recent Files', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user1).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
|
||||
describe('Favorites', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user1).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1, folder2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2, folder1, folder2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
|
||||
// [C217090]
|
||||
describe('Trash', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(user1).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([fileForDelete1, fileForDelete2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('Permanently delete'))
|
||||
.toBe(true, 'Permanently delete is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, 'Restore is not displayed for selected files');
|
||||
})
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folderForDelete1, folderForDelete2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('Permanently delete'))
|
||||
.toBe(true, 'Permanently delete is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, 'Restore is not displayed for selected files');
|
||||
})
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([fileForDelete1, fileForDelete2, folderForDelete1, folderForDelete2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('Permanently delete'))
|
||||
.toBe(true, 'Permanently delete is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, 'Restore is not displayed for selected files');
|
||||
})
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
});
|
||||
});
|
763
e2e/suites/actions/toolbar-single-selection.test.ts
Executable file
763
e2e/suites/actions/toolbar-single-selection.test.ts
Executable file
@ -0,0 +1,763 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Toolbar actions - single selection : ', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
const username2 = `user-${Utils.random()}`;
|
||||
|
||||
const fileUser = `file-${Utils.random()}.txt`; let fileUserId;
|
||||
|
||||
const folderUser = `folder-${Utils.random()}`; let folderUserId;
|
||||
|
||||
const fileForDelete = `file-${Utils.random()}.txt`; let fileForDeleteId;
|
||||
|
||||
const folderForDelete = `folder-${Utils.random()}`; let folderForDeleteId;
|
||||
|
||||
const siteName = `site-private-${Utils.random()}`;
|
||||
const fileAdmin = `file-${Utils.random()}.txt`;
|
||||
const folderAdmin = `folder-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, toolbar } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFiles([ fileUser ]))
|
||||
.then(resp => fileUserId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFiles([ fileForDelete ]))
|
||||
.then(resp => fileForDeleteId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolders([ folderForDelete ]))
|
||||
.then(resp => folderForDeleteId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolders([ folderUser ]))
|
||||
.then(resp => folderUserId = resp.data.entry.id)
|
||||
.then(() => apis.user.shared.shareFileById(fileUserId))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', fileUserId))
|
||||
.then(() => apis.user.favorites.addFavoriteById('folder', folderUserId))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodeById(fileUserId),
|
||||
apis.user.nodes.deleteNodeById(folderUserId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('General tests', () => {
|
||||
const userSite = `site-${Utils.random()}`;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.sites.createSite(userSite, SITE_VISIBILITY.PUBLIC)
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.sites.deleteSite(userSite),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('actions not displayed for top level of File Libraries', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.clickOnItemName(userSite))
|
||||
.then(() => expect(toolbar.actions.isEmpty()).toBe(true, 'toolbar not empty'));
|
||||
});
|
||||
|
||||
it('selected row is marked with a check circle icon', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.clickOnItemName(fileUser))
|
||||
.then(() => expect(dataTable.hasCheckMarkIcon(fileUser)).toBe(true, 'check mark missing'));
|
||||
});
|
||||
|
||||
describe('granular permissions', () => {
|
||||
const site = `site-${Utils.random()}`;
|
||||
const file1 = `file-${Utils.random()}`; let file1Id;
|
||||
const file2 = `file-${Utils.random()}`; let file2Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.sites.createSite(site, SITE_VISIBILITY.PRIVATE)
|
||||
.then(() => apis.admin.nodes.createFiles([ file1 ], `Sites/${site}/documentLibrary`)
|
||||
.then(resp => file1Id = resp.data.entry.id))
|
||||
.then(() => apis.admin.nodes.createFiles([ file2 ], `Sites/${site}/documentLibrary`)
|
||||
.then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.admin.sites.addSiteMember(site, username, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.admin.nodes.setGranularPermission(file1Id, false, username, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.admin.nodes.setGranularPermission(file2Id, false, username, SITE_ROLES.SITE_MANAGER))
|
||||
|
||||
.then(() => apis.user.shared.shareFileById(file1Id))
|
||||
.then(() => apis.admin.shared.shareFileById(file2Id))
|
||||
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 1 }))
|
||||
.then(() => apis.admin.shared.waitForApi({ expect: 1 }))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('file', [file1Id, file2Id]))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSite(site),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
describe('actions update accordingly for files with different granular permissions', () => {
|
||||
it('on File Libraries', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.doubleClickOnItemName(site))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.clickOnItemName(file1))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file1}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file1}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file1}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file1}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clickOnItemName(file2))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file2}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file2}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file2}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file2}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
xit('on Shared Files', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.clickOnItemName(file1))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file1}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file1}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file1}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file1}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clickOnItemName(file2))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file2}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file2}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file2}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file2}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
// disabled until ACA-1184 is done
|
||||
xit('on Favorites', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.clickOnItemName(file1))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file1}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file1}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file1}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${file1}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file1}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
.then(() => dataTable.clickOnItemName(file2))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file2}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file2}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file2}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${file2}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file2}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
describe('correct actions are displayed when selecting multiple files with different granular permissions', () => {
|
||||
it('on File Libraries', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.doubleClickOnItemName(site))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.selectMultipleItems([ file1, file2 ]))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
xit('on Shared Files', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.selectMultipleItems([ file1, file2 ]))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
// disabled until ACA-1184 is done
|
||||
xit('on Favorites', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.selectMultipleItems([ file1, file2 ]))
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
xit('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Personal Files', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('actions are displayed when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderUser}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
it('correct actions appear when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, `Edit is not displayed for ${folderUser}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderUser}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${folderUser}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${folderUser}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderUser}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Libraries', () => {
|
||||
beforeAll(done => {
|
||||
apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)
|
||||
.then(() => apis.admin.people.createUser(username2))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_MANAGER))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username2, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.admin.nodes.createFiles([ fileAdmin ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(() => apis.admin.nodes.createFolders([ folderAdmin ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.doubleClickOnItemName(siteName))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
apis.admin.sites.deleteSite(siteName).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('user is Manager', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileAdmin}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('actions are displayed when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderAdmin}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileAdmin}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileAdmin}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
it('correct actions appear when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, `Edit is not displayed for ${folderAdmin}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${folderAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${folderAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderAdmin}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
describe('user is Consumer', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username2).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileAdmin}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('actions are displayed when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderAdmin}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileAdmin}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${fileAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${fileAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileAdmin}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
it('correct actions appear when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderAdmin)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderAdmin}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${folderAdmin}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${folderAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${folderAdmin}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderAdmin}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Shared Files', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
dataTable.clearSelection();
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
describe('Recent Files', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
dataTable.clearSelection();
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
describe('Favorites', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('actions are displayed when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderUser}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
|
||||
it('correct actions appear when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderUser)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderUser}`);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, `Edit is not displayed for ${folderUser}`);
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderUser}`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${folderUser}`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${folderUser}`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderUser}`);
|
||||
})
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform());
|
||||
});
|
||||
});
|
||||
|
||||
// [C217090]
|
||||
describe('Trash', () => {
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.deleteNodeById(fileForDeleteId, false)
|
||||
.then(() => apis.user.nodes.deleteNodeById(folderForDeleteId, false))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.trashcan.permanentlyDelete(fileForDeleteId),
|
||||
apis.user.trashcan.permanentlyDelete(folderForDeleteId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('actions are not displayed when no item is selected', () => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`);
|
||||
});
|
||||
|
||||
it('actions are displayed when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileForDelete)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileForDelete}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('actions are displayed when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderForDelete)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderForDelete}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a file is selected', () => {
|
||||
dataTable.clickOnItemName(fileForDelete)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('Permanently delete'))
|
||||
.toBe(true, `Permanently delete is not displayed for ${fileForDelete}`);
|
||||
expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, `Restore is not displayed for ${fileForDelete}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('correct actions appear when a folder is selected', () => {
|
||||
dataTable.clickOnItemName(folderForDelete)
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('Permanently delete'))
|
||||
.toBe(true, `Permanently delete is displayed for ${folderForDelete}`);
|
||||
expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, `Restore is not enabled for ${folderForDelete}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
423
e2e/suites/actions/undo-delete.test.ts
Executable file
423
e2e/suites/actions/undo-delete.test.ts
Executable file
@ -0,0 +1,423 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Undo delete content', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, toolbar } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
apis.admin.trashcan.emptyTrash().then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on Personal Files', () => {
|
||||
const file1 = `file1-${Utils.random()}.txt`; let file1Id;
|
||||
const file2 = `file2-${Utils.random()}.txt`; let file2Id;
|
||||
const file3 = `file3-${Utils.random()}.txt`; let file3Id;
|
||||
const file4 = `file4-${Utils.random()}.txt`;
|
||||
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
|
||||
const folder2 = `folder2-${Utils.random()}`; let folder2Id;
|
||||
const fileLocked2 = `fileLocked2-${Utils.random()}.txt`; let fileLocked2Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(file1).then(resp => file1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(file2).then(resp => file2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file3).then(resp => file3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(file4, folder1Id))
|
||||
.then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(fileLocked2, folder2Id).then(resp => fileLocked2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.lockFile(fileLocked2Id))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.unlockFile(fileLocked2Id)
|
||||
.then(() => apis.user.nodes.deleteNodesById([file1Id, file2Id, file3Id, folder1Id, folder2Id]))
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Successful delete notification shows Undo action', () => {
|
||||
dataTable.clickOnItemName(file1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).toContain(`Undo`);
|
||||
})
|
||||
|
||||
.then(() => apis.user.trashcan.restore(file1Id));
|
||||
});
|
||||
|
||||
it('Unsuccessful delete notification does not show Undo action', () => {
|
||||
dataTable.clickOnItemName(folder2)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => {
|
||||
expect(message).not.toContain(`Undo`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Undo delete of file', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(file1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(file1).isPresent()).toBe(true, 'Item was not restored');
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Undo delete of folder with content', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(folder1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(folder1).isPresent()).toBe(true, 'Item was not restored');
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => dataTable.doubleClickOnItemName(folder1))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(file4).isPresent()).toBe(true, 'file from folder not restored');
|
||||
});
|
||||
});
|
||||
|
||||
it('undo delete of multiple files', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.selectMultipleItems([file2, file3])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(file2).isPresent()).toBe(true, `${file2} was not removed from list`);
|
||||
expect(dataTable.getRowName(file3).isPresent()).toBe(true, `${file3} was not removed from list`);
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Shared Files', () => {
|
||||
const sharedFile1 = `sharedFile1-${Utils.random()}`; let sharedFile1Id;
|
||||
const sharedFile2 = `sharedFile2-${Utils.random()}`; let sharedFile2Id;
|
||||
const sharedFile3 = `sharedFile3-${Utils.random()}`; let sharedFile3Id;
|
||||
const sharedFile4 = `sharedFile4-${Utils.random()}`; let sharedFile4Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(sharedFile1).then(resp => sharedFile1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(sharedFile2).then(resp => sharedFile2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(sharedFile3).then(resp => sharedFile3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(sharedFile4).then(resp => sharedFile4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.shared.shareFilesByIds([sharedFile1Id, sharedFile2Id, sharedFile3Id, sharedFile4Id]))
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 4 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.deleteNodesById([sharedFile2Id, sharedFile3Id, sharedFile4Id])
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Successful delete notification shows Undo action', () => {
|
||||
dataTable.clickOnItemName(sharedFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => expect(message).toContain(`Undo`));
|
||||
});
|
||||
|
||||
it('Undo delete of file', () => {
|
||||
dataTable.clickOnItemName(sharedFile2)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => expect(dataTable.getRowName(sharedFile2).isPresent()).toBe(false, 'Item was not restored'));
|
||||
});
|
||||
|
||||
it('undo delete of multiple files', () => {
|
||||
dataTable.selectMultipleItems([sharedFile3, sharedFile4])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(sharedFile3).isPresent()).toBe(false, `${sharedFile3} was not restored`);
|
||||
expect(dataTable.getRowName(sharedFile4).isPresent()).toBe(false, `${sharedFile4} was not restored`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Favorites', () => {
|
||||
const favoriteFile1 = `favFile1-${Utils.random()}.txt`; let favoriteFile1Id;
|
||||
const favoriteFile2 = `favFile2-${Utils.random()}.txt`; let favoriteFile2Id;
|
||||
const favoriteFile4 = `favFile4-${Utils.random()}.txt`;
|
||||
const favoriteFileLocked2 = `favFileLocked2-${Utils.random()}.txt`; let favoriteFileLocked2Id;
|
||||
const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id;
|
||||
const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(favoriteFile1).then(resp => favoriteFile1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(favoriteFile2).then(resp => favoriteFile2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolder(favoriteFolder1).then(resp => favoriteFolder1Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(favoriteFile4, favoriteFolder1Id))
|
||||
.then(() => apis.user.nodes.createFolder(favoriteFolder2).then(resp => favoriteFolder2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(favoriteFileLocked2, favoriteFolder2Id)
|
||||
.then(resp => favoriteFileLocked2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.lockFile(favoriteFileLocked2Id))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('file', [favoriteFile1Id, favoriteFile2Id]))
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('folder', [favoriteFolder1Id, favoriteFolder2Id]))
|
||||
.then(() => apis.user.favorites.waitForApi({ expect: 4 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.unlockFile(favoriteFileLocked2Id)
|
||||
.then(() => apis.user.nodes.deleteNodesById([favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id]))
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Successful delete notification shows Undo action', () => {
|
||||
dataTable.clickOnItemName(favoriteFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => expect(message).toContain(`Undo`))
|
||||
|
||||
.then(() => apis.user.trashcan.restore(favoriteFile1Id));
|
||||
});
|
||||
|
||||
it('Unsuccessful delete notification does not show Undo action', () => {
|
||||
dataTable.clickOnItemName(favoriteFolder2)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => expect(message).not.toContain(`Undo`));
|
||||
});
|
||||
|
||||
it('Undo delete of file', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(favoriteFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, 'Item was not restored');
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Undo delete of folder with content', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.clickOnItemName(favoriteFolder1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFolder1).isPresent()).toBe(true, 'Item was not restored');
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
})
|
||||
.then(() => dataTable.doubleClickOnItemName(favoriteFolder1))
|
||||
.then(() => expect(dataTable.getRowName(favoriteFile4).isPresent()).toBe(true, 'file from folder not restored'));
|
||||
});
|
||||
|
||||
it('undo delete of multiple files', () => {
|
||||
let items: number;
|
||||
page.dataTable.countRows().then(number => { items = number; });
|
||||
|
||||
dataTable.selectMultipleItems([favoriteFile1, favoriteFile2])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, `${favoriteFile1} was not removed from list`);
|
||||
expect(dataTable.getRowName(favoriteFile2).isPresent()).toBe(true, `${favoriteFile2} was not removed from list`);
|
||||
expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Recent Files', () => {
|
||||
const recentFile1 = `recentFile1-${Utils.random()}.txt`; let recentFile1Id;
|
||||
const recentFile2 = `recentFile2-${Utils.random()}.txt`; let recentFile2Id;
|
||||
const recentFile3 = `recentFile3-${Utils.random()}.txt`; let recentFile3Id;
|
||||
const recentFile4 = `recentFile4-${Utils.random()}.txt`; let recentFile4Id;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFile(recentFile1).then(resp => recentFile1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(recentFile2).then(resp => recentFile2Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(recentFile3).then(resp => recentFile3Id = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFile(recentFile4).then(resp => recentFile4Id = resp.data.entry.id))
|
||||
.then(() => apis.user.search.waitForApi(username, { expect: 4 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
|
||||
.then((): any => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.isEmptyList())
|
||||
.then(empty => {
|
||||
if (empty) {
|
||||
browser.sleep(6000).then(() => page.refresh());
|
||||
}
|
||||
})
|
||||
)
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
page.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
logoutPage.load(),
|
||||
apis.user.nodes.deleteNodesById([recentFile2Id, recentFile3Id, recentFile4Id])
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('Successful delete notification shows Undo action', () => {
|
||||
dataTable.clickOnItemName(recentFile1)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.getSnackBarMessage())
|
||||
.then(message => expect(message).toContain(`Undo`));
|
||||
});
|
||||
|
||||
// due to the fact that the search api is slow to update,
|
||||
// we cannot test that the restored file is displayed in the Recent Files list
|
||||
// without adding a very big browser.sleep followed by a page.refresh
|
||||
// so for the moment we're testing that the restored file is not displayed in the Trash
|
||||
xit('Undo delete of file', () => {
|
||||
dataTable.clickOnItemName(recentFile2)
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => expect(dataTable.getRowName(recentFile2).isPresent()).toBe(false, 'Item is in Trash'));
|
||||
});
|
||||
|
||||
// due to the fact that the search api is slow to update,
|
||||
// we cannot test that the restored file is displayed in the Recent Files list
|
||||
// without adding a very big browser.sleep followed by a page.refresh
|
||||
// so for the moment we're testing that the restored file is not displayed in the Trash
|
||||
xit('undo delete of multiple files', () => {
|
||||
dataTable.selectMultipleItems([recentFile3, recentFile4])
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(() => toolbar.actions.menu.clickMenuItem('Delete'))
|
||||
.then(() => page.clickSnackBarAction())
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => {
|
||||
expect(dataTable.getRowName(recentFile3).isPresent()).toBe(false, `${recentFile3} is in Trash`);
|
||||
expect(dataTable.getRowName(recentFile4).isPresent()).toBe(false, `${recentFile4} is in Trash`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
74
e2e/suites/actions/upload-file.test.ts
Executable file
74
e2e/suites/actions/upload-file.test.ts
Executable file
@ -0,0 +1,74 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// import { browser, protractor, promise } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
|
||||
describe('Upload files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
// apis.user.nodes.deleteNodeById(folder1Id),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Upload a file', () => {
|
||||
dataTable.doubleClickOnItemName(folder1)
|
||||
.then(() => page.sidenav.openNewMenu())
|
||||
.then(() => page.sidenav.menu.uploadFile().sendKeys(`${__dirname}/create-folder.test.ts`));
|
||||
});
|
||||
});
|
128
e2e/suites/application/page-titles.test.ts
Executable file
128
e2e/suites/application/page-titles.test.ts
Executable file
@ -0,0 +1,128 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
|
||||
describe('Page titles', () => {
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on Login / Logout pages', () => {
|
||||
it('on Login page', () => {
|
||||
loginPage.load()
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain('Sign in');
|
||||
});
|
||||
});
|
||||
|
||||
it('after logout', () => {
|
||||
loginPage.loginWithAdmin()
|
||||
.then(() => page.signOut())
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain('Sign in');
|
||||
});
|
||||
});
|
||||
|
||||
it('when pressing Back after Logout', () => {
|
||||
loginPage.loginWithAdmin()
|
||||
.then(() => page.signOut())
|
||||
.then(() => browser.navigate().back())
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain('Sign in');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on list views', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWithAdmin().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load()
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Personal Files page', () => {
|
||||
const label = SIDEBAR_LABELS.PERSONAL_FILES;
|
||||
|
||||
page.sidenav.navigateToLinkByLabel(label)
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain(label);
|
||||
});
|
||||
});
|
||||
|
||||
it('File Libraries page', () => {
|
||||
const label = SIDEBAR_LABELS.FILE_LIBRARIES;
|
||||
|
||||
page.sidenav.navigateToLinkByLabel(label)
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain(label);
|
||||
});
|
||||
});
|
||||
|
||||
it('Shared Files page', () => {
|
||||
const label = SIDEBAR_LABELS.SHARED_FILES;
|
||||
|
||||
page.sidenav.navigateToLinkByLabel(label)
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain(label);
|
||||
});
|
||||
});
|
||||
|
||||
it('Recent Files page', () => {
|
||||
const label = SIDEBAR_LABELS.RECENT_FILES;
|
||||
|
||||
page.sidenav.navigateToLinkByLabel(label)
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain(label);
|
||||
});
|
||||
});
|
||||
|
||||
it('Favorites page', () => {
|
||||
const label = SIDEBAR_LABELS.FAVORITES;
|
||||
|
||||
page.sidenav.navigateToLinkByLabel(label)
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain(label);
|
||||
});
|
||||
});
|
||||
|
||||
it('Trash page', () => {
|
||||
const label = SIDEBAR_LABELS.TRASH;
|
||||
|
||||
page.sidenav.navigateToLinkByLabel(label)
|
||||
.then(() => {
|
||||
expect(browser.getTitle()).toContain(label);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
239
e2e/suites/authentication/login.test.ts
Executable file
239
e2e/suites/authentication/login.test.ts
Executable file
@ -0,0 +1,239 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
|
||||
import { APP_ROUTES } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Login', () => {
|
||||
const peopleApi = new RepoClient().people;
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
|
||||
/* cspell:disable-next-line */
|
||||
const testUser = `user-${Utils.random()}@alfness`;
|
||||
|
||||
const russianUser = {
|
||||
/* cspell:disable-next-line */
|
||||
username: `пользвате${Utils.random()}`,
|
||||
password: '密碼中國'
|
||||
};
|
||||
|
||||
const johnDoe = {
|
||||
username: `user-${Utils.random()}`,
|
||||
get password() { return this.username; },
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
};
|
||||
|
||||
const disabledUser = `user-${Utils.random()}`;
|
||||
const testUser2 = {
|
||||
username: `user-${Utils.random()}`,
|
||||
password: 'user2 password'
|
||||
};
|
||||
const newPassword = 'new password';
|
||||
|
||||
beforeAll(done => {
|
||||
Promise
|
||||
.all([
|
||||
peopleApi.createUser(testUser),
|
||||
peopleApi.createUser(russianUser.username, russianUser.password),
|
||||
peopleApi.createUser(johnDoe.username, johnDoe.password, {
|
||||
firstName: johnDoe.firstName,
|
||||
lastName: johnDoe.lastName
|
||||
}),
|
||||
peopleApi.createUser(disabledUser).then(() => peopleApi.disableUser(disabledUser)),
|
||||
peopleApi.createUser(testUser2.username, testUser2.password)
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
logoutPage.load()
|
||||
.then(() => Utils.clearLocalStorage())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('general tests', () => {
|
||||
beforeEach(done => {
|
||||
loginPage.load().then(done);
|
||||
});
|
||||
|
||||
it('login page default values', () => {
|
||||
expect(loginPage.login.usernameInput.isEnabled()).toBe(true, 'username input is not enabled');
|
||||
expect(loginPage.login.passwordInput.isEnabled()).toBe(true, 'password input is not enabled');
|
||||
expect(loginPage.login.submitButton.isEnabled()).toBe(false, 'SIGN IN button is enabled');
|
||||
expect(loginPage.login.getPasswordVisibility()).toBe(false, 'Password is not hidden by default');
|
||||
});
|
||||
|
||||
it('change password visibility', () => {
|
||||
loginPage.login.enterPassword('some password');
|
||||
expect(loginPage.login.isPasswordShown()).toBe(false, 'password is visible');
|
||||
loginPage.login.passwordVisibility.click()
|
||||
.then(() => {
|
||||
expect(loginPage.login.getPasswordVisibility()).toBe(true, 'Password visibility not changed');
|
||||
expect(loginPage.login.isPasswordShown()).toBe(true, 'password is not visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with valid credentials', () => {
|
||||
it('navigate to "Personal Files"', () => {
|
||||
const { username } = johnDoe;
|
||||
|
||||
loginPage.loginWith(username)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
});
|
||||
});
|
||||
|
||||
it(`displays user's name in header`, () => {
|
||||
const { userInfo } = new BrowsingPage(APP_ROUTES.PERSONAL_FILES).header;
|
||||
const { username, firstName, lastName } = johnDoe;
|
||||
|
||||
loginPage.loginWith(username)
|
||||
.then(() => {
|
||||
expect(userInfo.name).toEqual(`${firstName} ${lastName}`);
|
||||
});
|
||||
});
|
||||
|
||||
it(`logs in with user having username containing "@"`, () => {
|
||||
loginPage
|
||||
.loginWith(testUser)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
});
|
||||
});
|
||||
|
||||
it('logs in with user with non-latin characters', () => {
|
||||
const { username, password } = russianUser;
|
||||
|
||||
loginPage
|
||||
.loginWith(username, password)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
});
|
||||
});
|
||||
|
||||
it('redirects to Home Page when navigating to the Login page while already logged in', () => {
|
||||
const { username } = johnDoe;
|
||||
|
||||
loginPage
|
||||
.loginWith(username)
|
||||
.then(() => browser.get(APP_ROUTES.LOGIN)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('redirects to Personal Files when pressing browser Back while already logged in ', () => {
|
||||
const { username } = johnDoe;
|
||||
|
||||
loginPage
|
||||
.loginWith(username)
|
||||
.then(() => browser.navigate().back())
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
});
|
||||
});
|
||||
|
||||
it('user is able to login after changing his password', () => {
|
||||
loginPage.loginWith(testUser2.username, testUser2.password)
|
||||
.then(() => logoutPage.load())
|
||||
.then(() => peopleApi.changePassword(testUser2.username, newPassword))
|
||||
.then(() => loginPage.loginWith(testUser2.username, newPassword))
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with invalid credentials', () => {
|
||||
const { login: loginComponent } = loginPage;
|
||||
const { submitButton, errorMessage } = loginComponent;
|
||||
|
||||
beforeEach(done => {
|
||||
loginPage.load().then(done);
|
||||
});
|
||||
|
||||
it('disabled submit button when no credentials are entered', () => {
|
||||
expect(submitButton.isEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it('disabled submit button when password is empty', () => {
|
||||
loginComponent.enterUsername('any-username');
|
||||
expect(submitButton.isEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it('disabled submit button when username is empty', () => {
|
||||
loginPage.login.enterPassword('any-password');
|
||||
expect(submitButton.isEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows error when entering nonexistent user', () => {
|
||||
loginPage
|
||||
.tryLoginWith('nonexistent-user', 'any-password')
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
expect(errorMessage.isDisplayed()).toBe(true);
|
||||
expect(errorMessage.getText()).toBe(`You've entered an unknown username or password`);
|
||||
});
|
||||
});
|
||||
|
||||
it('shows error when entering invalid password', () => {
|
||||
const { username } = johnDoe;
|
||||
|
||||
loginPage
|
||||
.tryLoginWith(username, 'incorrect-password')
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
expect(errorMessage.isDisplayed()).toBe(true);
|
||||
expect(errorMessage.getText()).toBe(`You've entered an unknown username or password`);
|
||||
});
|
||||
});
|
||||
|
||||
it('unauthenticated user is redirected to Login page', () => {
|
||||
browser.get(APP_ROUTES.PERSONAL_FILES)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
});
|
||||
});
|
||||
|
||||
it('disabled user is not logged in', () => {
|
||||
loginPage.tryLoginWith(disabledUser)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
expect(errorMessage.isDisplayed()).toBe(true);
|
||||
expect(errorMessage.getText()).toBe(`You've entered an unknown username or password`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
82
e2e/suites/authentication/logout.test.ts
Executable file
82
e2e/suites/authentication/logout.test.ts
Executable file
@ -0,0 +1,82 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
import { APP_ROUTES } from '../../configs';
|
||||
|
||||
describe('Logout', () => {
|
||||
const page = new BrowsingPage();
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
|
||||
const peopleApi = new RepoClient().people;
|
||||
|
||||
const johnDoe = `user-${Utils.random()}`;
|
||||
|
||||
beforeAll((done) => {
|
||||
peopleApi
|
||||
.createUser(johnDoe)
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach((done) => {
|
||||
loginPage.loginWith(johnDoe).then(done);
|
||||
});
|
||||
|
||||
afterEach((done) => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('Sign out option is available [C213143]', () => {
|
||||
page.header.userInfo.openMenu()
|
||||
.then(() => expect(page.header.userInfo.menu.isMenuItemPresent('Sign out')).toBe(true, 'Sign out option not displayed'));
|
||||
});
|
||||
|
||||
it('redirects to Login page on sign out [C213144]', () => {
|
||||
page.signOut()
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
});
|
||||
});
|
||||
|
||||
it('redirects to Login page when pressing browser Back after logout [C213145]', () => {
|
||||
page.signOut()
|
||||
.then(() => browser.navigate().back())
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
});
|
||||
});
|
||||
|
||||
it('redirects to Login page when trying to access a part of the app after logout [C213146]', () => {
|
||||
page.signOut()
|
||||
.then(() => page.load('/favorites'))
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN);
|
||||
});
|
||||
});
|
||||
});
|
108
e2e/suites/list-views/empty-list.test.ts
Executable file
108
e2e/suites/list-views/empty-list.test.ts
Executable file
@ -0,0 +1,108 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Empty list views', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
const password = username;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, password)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('empty Personal Files', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => {
|
||||
expect(dataTable.isEmptyList()).toBe(true, 'list is not empty');
|
||||
expect(dataTable.getEmptyDragAndDropText()).toContain('Drag and drop');
|
||||
});
|
||||
});
|
||||
|
||||
it('empty File Libraries [C217099]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => {
|
||||
expect(dataTable.isEmptyList()).toBe(true, 'list is not empty');
|
||||
expect(dataTable.getEmptyStateTitle()).toContain(`You aren't a member of any File Libraries yet`);
|
||||
expect(dataTable.getEmptyStateSubtitle()).toContain('Join sites to upload, view, and share files.');
|
||||
});
|
||||
});
|
||||
|
||||
it('empty Shared Files', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => {
|
||||
expect(dataTable.isEmptyList()).toBe(true, 'list is not empty');
|
||||
expect(dataTable.getEmptyStateTitle()).toContain('No shared files or folders');
|
||||
expect(dataTable.getEmptyStateSubtitle()).toContain('Items you share using the Share option are shown here.');
|
||||
});
|
||||
});
|
||||
|
||||
it('empty Recent Files [C213169]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => {
|
||||
expect(dataTable.isEmptyList()).toBe(true, 'list is not empty');
|
||||
expect(dataTable.getEmptyStateTitle()).toContain('No recent files');
|
||||
expect(dataTable.getEmptyStateSubtitle()).toContain('Items you upload or edit in the last 30 days are shown here.');
|
||||
});
|
||||
});
|
||||
|
||||
it('empty Favorites', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => {
|
||||
expect(dataTable.isEmptyList()).toBe(true, 'list is not empty');
|
||||
expect(dataTable.getEmptyStateTitle()).toContain('No favorite files or folders');
|
||||
expect(dataTable.getEmptyStateSubtitle()).toContain('Favorite items that you want to easily find later.');
|
||||
});
|
||||
});
|
||||
|
||||
it('empty Trash', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => {
|
||||
expect(dataTable.isEmptyList()).toBe(true, 'list is not empty');
|
||||
expect(dataTable.getEmptyStateTitle()).toContain('Trash is empty');
|
||||
expect(dataTable.getEmptyStateText()).toContain('Items you delete are moved to the Trash.');
|
||||
expect(dataTable.getEmptyStateText()).toContain('Empty Trash to permanently delete items.');
|
||||
});
|
||||
});
|
||||
});
|
156
e2e/suites/list-views/favorites.test.ts
Executable file
156
e2e/suites/list-views/favorites.test.ts
Executable file
@ -0,0 +1,156 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Favorites', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
const password = username;
|
||||
|
||||
const siteName = `site-${Utils.random()}`;
|
||||
const folderName = `folder-${Utils.random()}`;
|
||||
const fileName1 = `file1-${Utils.random()}.txt`;
|
||||
const fileName2 = `file2-${Utils.random()}.txt`;
|
||||
const fileName3 = `file3-${Utils.random()}.txt`; let file3Id;
|
||||
const fileName4 = `file4-${Utils.random()}.txt`; let file4Id;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, password)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const favoritesPage = new BrowsingPage();
|
||||
const { dataTable } = favoritesPage;
|
||||
const { breadcrumb } = favoritesPage.toolbar;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
|
||||
.then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_MANAGER))
|
||||
.then(() => apis.admin.nodes.createFiles([ fileName1 ], `Sites/${siteName}/documentLibrary`)
|
||||
.then(resp => apis.user.favorites.addFavoriteById('file', resp.data.entry.id)))
|
||||
.then(() => apis.user.nodes.createFolders([ folderName ])
|
||||
.then(resp => apis.user.favorites.addFavoriteById('folder', resp.data.entry.id)))
|
||||
.then(() => apis.user.nodes.createFiles([ fileName2 ], folderName)
|
||||
.then(resp => apis.user.favorites.addFavoriteById('file', resp.data.entry.id)))
|
||||
.then(() => apis.user.nodes.createFiles([ fileName3 ], folderName)
|
||||
.then(resp => file3Id = resp.data.entry.id)
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file3Id))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file3Id, false)))
|
||||
.then(() => apis.user.nodes.createFiles([ fileName4 ], folderName)
|
||||
.then(resp => file4Id = resp.data.entry.id)
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', file4Id))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file4Id, false))
|
||||
.then(() => apis.user.trashcan.restore(file4Id)))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
favoritesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSite(siteName),
|
||||
apis.user.nodes.deleteNodes([ folderName ]),
|
||||
apis.admin.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns', () => {
|
||||
const labels = [ 'Name', 'Location', 'Size', 'Modified', 'Modified by' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(5 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('displays the favorite files and folders [C213226]', () => {
|
||||
expect(dataTable.countRows()).toEqual(4, 'Incorrect number of items displayed');
|
||||
expect(dataTable.getRowName(fileName1).isPresent()).toBe(true, `${fileName1} not displayed`);
|
||||
expect(dataTable.getRowName(fileName2).isPresent()).toBe(true, `${fileName2} not displayed`);
|
||||
expect(dataTable.getRowName(folderName).isPresent()).toBe(true, `${folderName} not displayed`);
|
||||
});
|
||||
|
||||
it(`file not displayed if it's in the Trashcan [C213228]`, () => {
|
||||
expect(dataTable.getRowName(fileName3).isPresent()).not.toBe(true, `${fileName3} is displayed`);
|
||||
});
|
||||
|
||||
it(`file is displayed after it is restored from Trashcan [C213229]`, () => {
|
||||
expect(dataTable.getRowName(fileName4).isPresent()).toBe(true, `${fileName4} not displayed`);
|
||||
});
|
||||
|
||||
it('Location column displays the parent folder of the files [C213231]', () => {
|
||||
expect(dataTable.getItemLocation(fileName1).getText()).toEqual(siteName);
|
||||
expect(dataTable.getItemLocation(fileName2).getText()).toEqual(folderName);
|
||||
expect(dataTable.getItemLocation(folderName).getText()).toEqual('Personal Files');
|
||||
});
|
||||
|
||||
it('Location column displays a tooltip with the entire path of the file [C213671]', () => {
|
||||
expect(dataTable.getItemLocationTooltip(fileName1)).toEqual(`File Libraries/${siteName}`);
|
||||
expect(dataTable.getItemLocationTooltip(fileName2)).toEqual(`Personal Files/${folderName}`);
|
||||
expect(dataTable.getItemLocationTooltip(folderName)).toEqual('Personal Files');
|
||||
});
|
||||
|
||||
it('Location column redirect - item in user Home [C213650] [C260968]', () => {
|
||||
dataTable.clickItemLocation(folderName)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files' ]));
|
||||
});
|
||||
|
||||
it('Location column redirect - file in folder [C213650] [C260968]', () => {
|
||||
dataTable.clickItemLocation(fileName2)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', folderName ]));
|
||||
});
|
||||
|
||||
it('Location column redirect - file in site [C213650] [C260969]', () => {
|
||||
dataTable.clickItemLocation(fileName1)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName ]));
|
||||
});
|
||||
|
||||
it('Navigate into folder from Favorites [C213230]', () => {
|
||||
dataTable.doubleClickOnItemName(folderName)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => breadcrumb.getCurrentItemName())
|
||||
.then(name => {
|
||||
expect(name).toBe(folderName);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
161
e2e/suites/list-views/file-libraries.test.ts
Executable file
161
e2e/suites/list-views/file-libraries.test.ts
Executable file
@ -0,0 +1,161 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { by } from 'protractor';
|
||||
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('File Libraries', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
const password = username;
|
||||
|
||||
const sitePrivate = `private-${Utils.random()}`;
|
||||
const siteModerated = `moderated-${Utils.random()}`;
|
||||
const sitePublic = `public-${Utils.random()}`;
|
||||
const siteName = `siteName-${Utils.random()}`;
|
||||
const siteId1 = Utils.random();
|
||||
const siteId2 = Utils.random();
|
||||
const adminSite = `admin-${Utils.random()}`;
|
||||
|
||||
const siteDescription = 'my site description';
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, password)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const fileLibrariesPage = new BrowsingPage();
|
||||
const { dataTable } = fileLibrariesPage;
|
||||
|
||||
beforeAll(done => {
|
||||
Promise
|
||||
.all([
|
||||
apis.admin.people.createUser(username),
|
||||
apis.admin.sites.createSite(sitePublic, SITE_VISIBILITY.PUBLIC),
|
||||
apis.admin.sites.createSite(siteModerated, SITE_VISIBILITY.MODERATED, { description: siteDescription }),
|
||||
apis.admin.sites.createSite(sitePrivate, SITE_VISIBILITY.PRIVATE, { description: '' }),
|
||||
apis.admin.sites.createSite(adminSite, SITE_VISIBILITY.PUBLIC),
|
||||
apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC, { id: siteId1 }),
|
||||
apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC, { id: siteId2 })
|
||||
])
|
||||
.then(() => apis.admin.sites.addSiteMember(sitePublic, username, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteModerated, username, SITE_ROLES.SITE_MANAGER))
|
||||
.then(() => apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_CONTRIBUTOR))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteId1, username, SITE_ROLES.SITE_CONTRIBUTOR))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteId2, username, SITE_ROLES.SITE_CONTRIBUTOR))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
fileLibrariesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSites([
|
||||
sitePublic,
|
||||
siteModerated,
|
||||
sitePrivate,
|
||||
adminSite,
|
||||
siteId1,
|
||||
siteId2
|
||||
]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns', () => {
|
||||
const labels = [ 'Title', 'Status' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(2 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('User can see only the sites he is a member of [C217095]', () => {
|
||||
const sitesCount = dataTable.countRows();
|
||||
|
||||
const expectedSites = {
|
||||
[sitePrivate]: SITE_VISIBILITY.PRIVATE,
|
||||
[siteModerated]: SITE_VISIBILITY.MODERATED,
|
||||
[sitePublic]: SITE_VISIBILITY.PUBLIC
|
||||
};
|
||||
|
||||
expect(sitesCount).toEqual(5, 'Incorrect number of sites displayed');
|
||||
expect(dataTable.getRowName(adminSite).isPresent()).toBe(false, 'Incorrect site appears in list');
|
||||
|
||||
dataTable.getRows()
|
||||
.map((row) => {
|
||||
return row.all(dataTable.cell).map(cell => cell.getText());
|
||||
})
|
||||
.then((rowCells) => {
|
||||
return rowCells.reduce((acc, cell) => {
|
||||
acc[cell[1]] = cell[2].toUpperCase();
|
||||
return acc;
|
||||
}, {});
|
||||
})
|
||||
.then((sitesList) => {
|
||||
Object.keys(expectedSites).forEach((site) => {
|
||||
expect(sitesList[site]).toEqual(expectedSites[site]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Site ID is displayed when two sites have the same name [C217098]', () => {
|
||||
const expectedSites = [
|
||||
`${siteName} (${siteId1})`,
|
||||
`${siteName} (${siteId2})`
|
||||
];
|
||||
dataTable.getCellsContainingName(siteName)
|
||||
.then(resp => {
|
||||
const expectedJSON = JSON.stringify(expectedSites.sort());
|
||||
const actualJSON = JSON.stringify(resp.sort());
|
||||
expect(actualJSON).toEqual(expectedJSON);
|
||||
});
|
||||
});
|
||||
|
||||
it('Tooltip for sites without description [C217096]', () => {
|
||||
const tooltip = dataTable.getItemNameTooltip(sitePrivate);
|
||||
expect(tooltip).toBe(`${sitePrivate}`);
|
||||
});
|
||||
|
||||
it('Tooltip for sites with description [C217097]', () => {
|
||||
const tooltip = dataTable.getItemNameTooltip(siteModerated);
|
||||
expect(tooltip).toBe(`${siteDescription}`);
|
||||
});
|
||||
});
|
181
e2e/suites/list-views/permissions.test.ts
Executable file
181
e2e/suites/list-views/permissions.test.ts
Executable file
@ -0,0 +1,181 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Special permissions', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
const password = username;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, password)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const recentFilesPage = new BrowsingPage();
|
||||
const favoritesPage = new BrowsingPage();
|
||||
const sharedPage = new BrowsingPage();
|
||||
const { dataTable } = recentFilesPage;
|
||||
|
||||
xit('');
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
describe('file not displayed if user no longer has permissions on it', () => {
|
||||
const sitePrivate = `private-${Utils.random()}`;
|
||||
const fileName = `file-${Utils.random()}.txt`;
|
||||
let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.sites.createSite(sitePrivate, SITE_VISIBILITY.PRIVATE)
|
||||
.then(() => apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_COLLABORATOR))
|
||||
.then(() => apis.admin.nodes.createFiles([ fileName ], `Sites/${sitePrivate}/documentLibrary`)
|
||||
.then(resp => fileId = resp.data.entry.id))
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', fileId))
|
||||
.then(() => apis.admin.shared.shareFileById(fileId))
|
||||
.then(() => apis.user.nodes.editNodeContent(fileId, 'edited by user'))
|
||||
|
||||
.then(() => apis.user.search.waitForApi(username, { expect: 1 }))
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 1 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_COLLABORATOR).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSite(sitePrivate),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('on Recent Files [C213173]', () => {
|
||||
recentFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items');
|
||||
})
|
||||
.then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username))
|
||||
.then(() => recentFilesPage.refresh())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(0, 'Incorrect number of items');
|
||||
});
|
||||
});
|
||||
|
||||
it('on Favorites [C213227]', () => {
|
||||
favoritesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items');
|
||||
})
|
||||
.then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username))
|
||||
.then(() => favoritesPage.refresh())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(0, 'Incorrect number of items');
|
||||
});
|
||||
});
|
||||
|
||||
it('on Shared Files [C213116]', () => {
|
||||
sharedPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items');
|
||||
})
|
||||
.then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username))
|
||||
.then(() => sharedPage.refresh())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(0, 'Incorrect number of items');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe(`Location column is empty if user doesn't have permissions on the file's parent folder`, () => {
|
||||
const sitePrivate = `private-${Utils.random()}`;
|
||||
const fileName = `file-${Utils.random()}.txt`;
|
||||
let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.sites.createSite(sitePrivate, SITE_VISIBILITY.PRIVATE)
|
||||
.then(() => apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_COLLABORATOR))
|
||||
.then(() => apis.admin.sites.getDocLibId(sitePrivate))
|
||||
.then(resp => apis.user.nodes.createFile(fileName, resp))
|
||||
.then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => apis.user.favorites.addFavoriteById('file', fileId))
|
||||
.then(() => apis.user.shared.shareFileById(fileId))
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 1 }))
|
||||
.then(() => apis.user.search.waitForApi(username, { expect: 1 }))
|
||||
.then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSite(sitePrivate),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it(`on Recent Files [C213178]`, () => {
|
||||
recentFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items');
|
||||
expect(dataTable.getItemLocation(fileName).getText()).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
it(`on Favorites [C213672]`, () => {
|
||||
favoritesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items');
|
||||
expect(dataTable.getItemLocation(fileName).getText()).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
it(`on Shared Files [C213668]`, () => {
|
||||
sharedPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items');
|
||||
expect(dataTable.getItemLocation(fileName).getText()).toEqual('');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
176
e2e/suites/list-views/personal-files.test.ts
Executable file
176
e2e/suites/list-views/personal-files.test.ts
Executable file
@ -0,0 +1,176 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
|
||||
import { SIDEBAR_LABELS, APP_ROUTES } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Personal Files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const personalFilesPage = new BrowsingPage();
|
||||
const { dataTable } = personalFilesPage;
|
||||
|
||||
const adminFolder = `admin-folder-${Utils.random()}`;
|
||||
|
||||
const userFolder = `user-folder-${Utils.random()}`;
|
||||
const userFile = `file-${Utils.random()}.txt`;
|
||||
|
||||
beforeAll(done => {
|
||||
Promise
|
||||
.all([
|
||||
apis.admin.people.createUser(username),
|
||||
apis.admin.nodes.createFolders([ adminFolder ])
|
||||
])
|
||||
.then(() => apis.user.nodes.createFolders([ userFolder ]))
|
||||
.then(() => apis.user.nodes.createFiles([ userFile ], userFolder))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise
|
||||
.all([
|
||||
apis.admin.nodes.deleteNodes([ adminFolder ]),
|
||||
apis.user.nodes.deleteNodes([ userFolder ])
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe(`Admin user's personal files`, () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWithAdmin().then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('has "Data Dictionary" folder [C213241]', () => {
|
||||
expect(dataTable.getRowName('Data Dictionary').isPresent()).toBe(true);
|
||||
});
|
||||
|
||||
it('has created content', () => {
|
||||
expect(dataTable.getRowName(adminFolder).isPresent()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`Regular user's personal files`, () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns [C217142]', () => {
|
||||
const labels = [ 'Name', 'Size', 'Modified', 'Modified by' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(4 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('has default sorted column [C217143]', () => {
|
||||
expect(dataTable.getSortedColumnHeader().getText()).toBe('Modified');
|
||||
});
|
||||
|
||||
it('has user created content [C213242]', () => {
|
||||
expect(dataTable.getRowName(userFolder).isPresent())
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it('navigates to folder [C213244]', () => {
|
||||
const getNodeIdPromise = apis.user.nodes
|
||||
.getNodeByPath(`/${userFolder}`)
|
||||
.then(response => response.data.entry.id);
|
||||
|
||||
const navigatePromise = dataTable
|
||||
.doubleClickOnItemName(userFolder)
|
||||
.then(() => dataTable.waitForHeader());
|
||||
|
||||
Promise
|
||||
.all([
|
||||
getNodeIdPromise,
|
||||
navigatePromise
|
||||
])
|
||||
.then(([ nodeId ]) => {
|
||||
expect(browser.getCurrentUrl())
|
||||
.toContain(nodeId, 'Node ID is not in the URL');
|
||||
|
||||
expect(dataTable.getRowName(userFile).isPresent())
|
||||
.toBe(true, 'user file is missing');
|
||||
});
|
||||
});
|
||||
|
||||
it('redirects to Personal Files on clicking the link from sidebar [C213245]', () => {
|
||||
personalFilesPage.dataTable.doubleClickOnItemName(userFolder)
|
||||
.then(() => personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES))
|
||||
.then(() => browser.getCurrentUrl())
|
||||
.then(url => expect(url.endsWith(APP_ROUTES.PERSONAL_FILES)).toBe(true, 'incorrect url'));
|
||||
});
|
||||
|
||||
it('page loads correctly after browser refresh [C213246]', () => {
|
||||
personalFilesPage.refresh()
|
||||
.then(() => expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES));
|
||||
});
|
||||
|
||||
it('page load by URL [C213247]', () => {
|
||||
let url;
|
||||
browser.getCurrentUrl()
|
||||
.then(resp => url = resp)
|
||||
.then(() => personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => browser.get(url))
|
||||
.then(() => expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES));
|
||||
});
|
||||
});
|
||||
});
|
141
e2e/suites/list-views/recent-files.test.ts
Executable file
141
e2e/suites/list-views/recent-files.test.ts
Executable file
@ -0,0 +1,141 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SITE_VISIBILITY, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Recent Files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const folderName = `folder-${Utils.random()}`; let folderId;
|
||||
const fileName1 = `file-${Utils.random()}.txt`;
|
||||
const fileName2 = `file-${Utils.random()}.txt`; let file2Id;
|
||||
const fileName3 = `file-${Utils.random()}.txt`;
|
||||
|
||||
const siteName = `site-${Utils.random()}`;
|
||||
const folderSite = `folder2-${Utils.random()}`; let folderSiteId;
|
||||
const fileSite = `file-${Utils.random()}.txt`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const recentFilesPage = new BrowsingPage();
|
||||
const { dataTable } = recentFilesPage;
|
||||
const { breadcrumb } = recentFilesPage.toolbar;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFolders([ folderName ])).then(resp => folderId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFiles([ fileName1 ], folderName))
|
||||
.then(() => apis.user.nodes.createFiles([ fileName2 ])).then(resp => file2Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFiles([ fileName3 ]).then(resp => apis.user.nodes.deleteNodeById(resp.data.entry.id, false)))
|
||||
|
||||
.then(() => apis.user.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC))
|
||||
.then(() => apis.user.sites.getDocLibId(siteName))
|
||||
.then(resp => apis.user.nodes.createFolder(folderSite, resp)).then(resp => folderSiteId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(fileSite, folderSiteId))
|
||||
|
||||
.then(() => apis.user.search.waitForApi(username, { expect: 3 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
recentFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodesById([ folderId, file2Id ]),
|
||||
apis.user.sites.deleteSite(siteName),
|
||||
apis.admin.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns [C213168]', () => {
|
||||
const labels = [ 'Name', 'Location', 'Size', 'Modified' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(4 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('default sorting column [C213171]', () => {
|
||||
expect(dataTable.getSortedColumnHeader().getText()).toBe('Modified');
|
||||
expect(dataTable.getSortingOrder()).toBe('desc');
|
||||
});
|
||||
|
||||
it('displays the files added by the current user in the last 30 days [C213170]', () => {
|
||||
expect(dataTable.countRows()).toEqual(3, 'Incorrect number of files displayed');
|
||||
expect(dataTable.getRowName(fileName1).isPresent()).toBe(true, `${fileName1} not displayed`);
|
||||
expect(dataTable.getRowName(fileName2).isPresent()).toBe(true, `${fileName2} not displayed`);
|
||||
expect(dataTable.getRowName(fileSite).isPresent()).toBe(true, `${fileSite} not displayed`);
|
||||
});
|
||||
|
||||
it(`file not displayed if it's in the Trashcan [C213174]`, () => {
|
||||
expect(dataTable.getRowName(fileName3).isPresent()).not.toBe(true, `${fileName3} is displayed`);
|
||||
});
|
||||
|
||||
it('Location column displays the parent folder of the file [C213175]', () => {
|
||||
expect(dataTable.getItemLocation(fileName1).getText()).toEqual(folderName);
|
||||
expect(dataTable.getItemLocation(fileName2).getText()).toEqual('Personal Files');
|
||||
expect(dataTable.getItemLocation(fileSite).getText()).toEqual(folderSite);
|
||||
});
|
||||
|
||||
it('Location column displays a tooltip with the entire path of the file [C213177]', () => {
|
||||
expect(dataTable.getItemLocationTooltip(fileName1)).toEqual(`Personal Files/${folderName}`);
|
||||
expect(dataTable.getItemLocationTooltip(fileName2)).toEqual('Personal Files');
|
||||
expect(dataTable.getItemLocationTooltip(fileSite)).toEqual(`File Libraries/${siteName}/${folderSite}`);
|
||||
});
|
||||
|
||||
it('Location column redirect - file in user Home [C213176] [C260968]', () => {
|
||||
dataTable.clickItemLocation(fileName2)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files' ]));
|
||||
});
|
||||
|
||||
it('Location column redirect - file in folder [C213176] [C260968]', () => {
|
||||
dataTable.clickItemLocation(fileName1)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', folderName ]));
|
||||
});
|
||||
|
||||
it('Location column redirect - file in site [C213176] [C260969]', () => {
|
||||
dataTable.clickItemLocation(fileSite)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName, folderSite ]));
|
||||
});
|
||||
});
|
142
e2e/suites/list-views/shared-files.test.ts
Executable file
142
e2e/suites/list-views/shared-files.test.ts
Executable file
@ -0,0 +1,142 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Shared Files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
const password = username;
|
||||
|
||||
const siteName = `site-${Utils.random()}`;
|
||||
const fileAdmin = `file-${Utils.random()}.txt`;
|
||||
|
||||
const folderUser = `folder-${Utils.random()}`;
|
||||
const file1User = `file1-${Utils.random()}.txt`; let file1Id;
|
||||
const file2User = `file2-${Utils.random()}.txt`; let file2Id;
|
||||
const file3User = `file3-${Utils.random()}.txt`; let file3Id;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, password)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const sharedFilesPage = new BrowsingPage();
|
||||
const { dataTable } = sharedFilesPage;
|
||||
const { breadcrumb } = sharedFilesPage.toolbar;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER))
|
||||
.then(() => apis.admin.nodes.createFiles([ fileAdmin ], `Sites/${siteName}/documentLibrary`))
|
||||
.then(resp => apis.admin.shared.shareFileById(resp.data.entry.id))
|
||||
|
||||
.then(() => apis.user.nodes.createFolders([ folderUser ]))
|
||||
.then(() => apis.user.nodes.createFiles([ file1User ], folderUser)).then(resp => file1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(file2User)).then(resp => file2Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(file3User)).then(resp => file3Id = resp.data.entry.id)
|
||||
.then(() => apis.user.shared.shareFilesByIds([file1Id, file2Id, file3Id]))
|
||||
|
||||
.then(() => apis.user.shared.waitForApi({ expect: 4 }))
|
||||
.then(() => apis.user.nodes.deleteNodeById(file2Id))
|
||||
.then(() => apis.user.shared.unshareFile(file3User))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
sharedFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
sharedFilesPage.refresh().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSite(siteName),
|
||||
apis.user.nodes.deleteNodes([ folderUser ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns [C213113]', () => {
|
||||
const labels = [ 'Name', 'Location', 'Size', 'Modified', 'Modified by', 'Shared by' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(6 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('default sorting column [C213115]', () => {
|
||||
expect(dataTable.getSortedColumnHeader().getText()).toBe('Modified');
|
||||
expect(dataTable.getSortingOrder()).toBe('desc');
|
||||
});
|
||||
|
||||
it('displays the files shared by everyone [C213114]', () => {
|
||||
expect(dataTable.getRowName(fileAdmin).isPresent()).toBe(true, `${fileAdmin} not displayed`);
|
||||
expect(dataTable.getRowName(file1User).isPresent()).toBe(true, `${file1User} not displayed`);
|
||||
});
|
||||
|
||||
it(`file not displayed if it's in the Trashcan [C213117]`, () => {
|
||||
expect(dataTable.getRowName(file2User).isPresent()).toBe(false, `${file2User} is displayed`);
|
||||
});
|
||||
|
||||
xit('unshared file is not displayed [C213118]', () => {
|
||||
expect(dataTable.getRowName(file3User).isPresent()).toBe(false, `${file3User} is displayed`);
|
||||
});
|
||||
|
||||
it('Location column displays the parent folder of the file [C213665]', () => {
|
||||
expect(dataTable.getItemLocation(fileAdmin).getText()).toEqual(siteName);
|
||||
expect(dataTable.getItemLocation(file1User).getText()).toEqual(folderUser);
|
||||
});
|
||||
|
||||
it('Location column redirect - file in user Home [C213666] [C260968]', () => {
|
||||
dataTable.clickItemLocation(file1User)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', folderUser ]));
|
||||
});
|
||||
|
||||
it('Location column redirect - file in site [C213666] [C260969]', () => {
|
||||
dataTable.clickItemLocation(fileAdmin)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName ]));
|
||||
});
|
||||
|
||||
it('Location column displays a tooltip with the entire path of the file [C213667]', () => {
|
||||
expect(dataTable.getItemLocationTooltip(fileAdmin)).toEqual(`File Libraries/${siteName}`);
|
||||
expect(dataTable.getItemLocationTooltip(file1User)).toEqual(`Personal Files/${folderUser}`);
|
||||
});
|
||||
});
|
330
e2e/suites/list-views/tooltips.test.ts
Executable file
330
e2e/suites/list-views/tooltips.test.ts
Executable file
@ -0,0 +1,330 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('File / folder tooltips', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
|
||||
const file = `file1-${Utils.random()}`;
|
||||
const fileWithDesc = `file2-${Utils.random()}`;
|
||||
const fileWithTitle = `file3-${Utils.random()}`;
|
||||
const fileWithTitleAndDesc = `file4-${Utils.random()}`;
|
||||
const fileNameEqTitleEqDesc = `file5-${Utils.random()}`;
|
||||
const fileNameEqTitleDiffDesc = `file6-${Utils.random()}`;
|
||||
const fileNameEqDescDiffTitle = `file7-${Utils.random()}`;
|
||||
const fileTitleEqDesc = `file8-${Utils.random()}`;
|
||||
let parentId, file1Id, file2Id, file3Id, file4Id, file5Id, file6Id, file7Id, file8Id;
|
||||
|
||||
const fileTitle = 'file title';
|
||||
const fileDescription = 'file description';
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFolder( parent ))
|
||||
.then(resp => parentId = resp.data.entry.id)
|
||||
|
||||
.then(() => Promise.all([
|
||||
apis.user.nodes.createFile(file, parentId).then(resp => file1Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileWithDesc, parentId, '', fileDescription).then(resp => file2Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileWithTitle, parentId, fileTitle).then(resp => file3Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileWithTitleAndDesc, parentId, fileTitle, fileDescription)
|
||||
.then(resp => file4Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileNameEqTitleEqDesc, parentId, fileNameEqTitleEqDesc, fileNameEqTitleEqDesc)
|
||||
.then(resp => file5Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileNameEqTitleDiffDesc, parentId, fileNameEqTitleDiffDesc, fileDescription)
|
||||
.then(resp => file6Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileNameEqDescDiffTitle, parentId, fileTitle, fileNameEqDescDiffTitle)
|
||||
.then(resp => file7Id = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileTitleEqDesc, parentId, fileTitle, fileTitle).then(resp => file8Id = resp.data.entry.id)
|
||||
]))
|
||||
|
||||
.then(() => apis.user.shared.shareFilesByIds([ file1Id, file2Id, file3Id, file4Id, file5Id, file6Id, file7Id, file8Id ]))
|
||||
|
||||
.then(() => apis.user.favorites.addFavoritesByIds('file', [
|
||||
file1Id, file2Id, file3Id, file4Id, file5Id, file6Id, file7Id, file8Id
|
||||
]))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodes([ parent ]),
|
||||
apis.admin.trashcan.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on Personal Files', () => {
|
||||
beforeAll(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.doubleClickOnItemName(parent))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('File with name, no title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`);
|
||||
});
|
||||
|
||||
it('File with name and description, no title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all different', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all equal', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`);
|
||||
});
|
||||
|
||||
it('File with name = title, different description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name = description, different title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`);
|
||||
});
|
||||
|
||||
it('File with title = description, different name', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Recent Files', () => {
|
||||
beforeAll(done => {
|
||||
apis.user.search.waitForApi(username, { expect: 8 })
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('File with name, no title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`);
|
||||
});
|
||||
|
||||
it('File with name and description, no title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all different', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all equal', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`);
|
||||
});
|
||||
|
||||
it('File with name = title, different description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name = description, different title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`);
|
||||
});
|
||||
|
||||
it('File with title = description, different name', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`);
|
||||
});
|
||||
});
|
||||
|
||||
// disabled until ACA-518 is done
|
||||
xdescribe('on Shared Files', () => {
|
||||
beforeAll(done => {
|
||||
apis.user.shared.waitForApi({ expect: 8 })
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('File with name, no title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`);
|
||||
});
|
||||
|
||||
it('File with name and description, no title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all different', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all equal', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`);
|
||||
});
|
||||
|
||||
it('File with name = title, different description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name = description, different title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`);
|
||||
});
|
||||
|
||||
it('File with title = description, different name', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Favorites', () => {
|
||||
beforeAll(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES).then(done);
|
||||
});
|
||||
|
||||
it('File with name, no title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`);
|
||||
});
|
||||
|
||||
it('File with name and description, no title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all different', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all equal', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`);
|
||||
});
|
||||
|
||||
it('File with name = title, different description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name = description, different title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`);
|
||||
});
|
||||
|
||||
it('File with title = description, different name', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on Trash', () => {
|
||||
const parentForTrash = `parent-${Utils.random()}`;
|
||||
let parentForTrashId, file1TrashId, file2TrashId, file3TrashId, file4TrashId;
|
||||
let file5TrashId, file6TrashId, file7TrashId, file8TrashId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.user.nodes.createFolder( parentForTrash )
|
||||
.then(resp => parentForTrashId = resp.data.entry.id)
|
||||
.then(() => Promise.all([
|
||||
apis.user.nodes.createFile(file, parentForTrashId)
|
||||
.then(resp => file1TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileWithDesc, parentForTrashId, '', fileDescription)
|
||||
.then(resp => file2TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileWithTitle, parentForTrashId, fileTitle)
|
||||
.then(resp => file3TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileWithTitleAndDesc, parentForTrashId, fileTitle, fileDescription)
|
||||
.then(resp => file4TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileNameEqTitleEqDesc, parentForTrashId, fileNameEqTitleEqDesc, fileNameEqTitleEqDesc)
|
||||
.then(resp => file5TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileNameEqTitleDiffDesc, parentForTrashId, fileNameEqTitleDiffDesc, fileDescription)
|
||||
.then(resp => file6TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileNameEqDescDiffTitle, parentForTrashId, fileTitle, fileNameEqDescDiffTitle)
|
||||
.then(resp => file7TrashId = resp.data.entry.id),
|
||||
apis.user.nodes.createFile(fileTitleEqDesc, parentForTrashId, fileTitle, fileTitle)
|
||||
.then(resp => file8TrashId = resp.data.entry.id)
|
||||
]))
|
||||
|
||||
.then(() => apis.user.nodes.deleteNodesById([
|
||||
file1TrashId, file2TrashId, file3TrashId, file4TrashId, file5TrashId, file6TrashId, file7TrashId, file8TrashId
|
||||
], false))
|
||||
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
apis.user.nodes.deleteNodes([ parentForTrash ]).then(done);
|
||||
});
|
||||
|
||||
it('File with name, no title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`);
|
||||
});
|
||||
|
||||
it('File with name and description, no title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title, no description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all different', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name and title and description, all equal', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`);
|
||||
});
|
||||
|
||||
it('File with name = title, different description', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`);
|
||||
});
|
||||
|
||||
it('File with name = description, different title', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`);
|
||||
});
|
||||
|
||||
it('File with title = description, different name', () => {
|
||||
expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`);
|
||||
});
|
||||
});
|
||||
});
|
169
e2e/suites/list-views/trash.test.ts
Executable file
169
e2e/suites/list-views/trash.test.ts
Executable file
@ -0,0 +1,169 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Trash', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const siteName = `site-${Utils.random()}`;
|
||||
const fileSite = `file-${Utils.random()}.txt`; let fileSiteId;
|
||||
|
||||
const folderAdmin = `folder-${Utils.random()}`; let folderAdminId;
|
||||
const fileAdmin = `file-${Utils.random()}.txt`; let fileAdminId;
|
||||
|
||||
const folderUser = `folder-${Utils.random()}`; let folderUserId;
|
||||
const fileUser = `file-${Utils.random()}.txt`; let fileUserId;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const trashPage = new BrowsingPage();
|
||||
const { dataTable } = trashPage;
|
||||
const { breadcrumb } = trashPage.toolbar;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.admin.nodes.createFiles([ fileAdmin ]).then(resp => fileAdminId = resp.data.entry.id))
|
||||
.then(() => apis.admin.nodes.createFolders([ folderAdmin ]).then(resp => folderAdminId = resp.data.entry.id))
|
||||
.then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC))
|
||||
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_MANAGER))
|
||||
.then(() => apis.admin.nodes.createFiles([ fileSite ], `Sites/${siteName}/documentLibrary`)
|
||||
.then(resp => fileSiteId = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFiles([ fileUser ]).then(resp => fileUserId = resp.data.entry.id))
|
||||
.then(() => apis.user.nodes.createFolders([ folderUser ]).then(resp => folderUserId = resp.data.entry.id))
|
||||
|
||||
.then(() => apis.admin.nodes.deleteNodesById([ fileAdminId, folderAdminId ], false))
|
||||
.then(() => apis.user.nodes.deleteNodesById([ fileSiteId, fileUserId, folderUserId ], false))
|
||||
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.admin.sites.deleteSite(siteName),
|
||||
apis.admin.trashcan.emptyTrash()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('as admin', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWithAdmin().then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
trashPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns', () => {
|
||||
const labels = [ 'Name', 'Location', 'Size', 'Deleted', 'Deleted by' ];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(5 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('displays the files and folders deleted by everyone [C213217]', () => {
|
||||
expect(dataTable.countRows()).toEqual(5, 'Incorrect number of deleted items displayed');
|
||||
|
||||
expect(dataTable.getRowName(fileAdmin).isPresent()).toBe(true, `${fileAdmin} not displayed`);
|
||||
expect(dataTable.getRowName(folderAdmin).isPresent()).toBe(true, `${folderAdmin} not displayed`);
|
||||
expect(dataTable.getRowName(fileUser).isPresent()).toBe(true, `${fileUser} not displayed`);
|
||||
expect(dataTable.getRowName(folderUser).isPresent()).toBe(true, `${folderUser} not displayed`);
|
||||
expect(dataTable.getRowName(fileSite).isPresent()).toBe(true, `${fileSite} not displayed`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('as user', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
trashPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('has the correct columns', () => {
|
||||
const labels = [ 'Name', 'Location', 'Size', 'Deleted'];
|
||||
const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label));
|
||||
|
||||
expect(dataTable.getColumnHeaders().count()).toBe(4 + 1, 'Incorrect number of columns');
|
||||
|
||||
elements.forEach((element, index) => {
|
||||
expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`);
|
||||
});
|
||||
});
|
||||
|
||||
it('displays the files and folders deleted by the user [C213218]', () => {
|
||||
expect(dataTable.countRows()).toEqual(3, 'Incorrect number of deleted items displayed');
|
||||
|
||||
expect(dataTable.getRowName(fileSite).isPresent()).toBe(true, `${fileSite} not displayed`);
|
||||
expect(dataTable.getRowName(fileUser).isPresent()).toBe(true, `${fileUser} not displayed`);
|
||||
expect(dataTable.getRowName(folderUser).isPresent()).toBe(true, `${folderUser} not displayed`);
|
||||
expect(dataTable.getRowName(fileAdmin).isPresent()).toBe(false, `${fileAdmin} is displayed`);
|
||||
});
|
||||
|
||||
it('default sorting column [C213219]', () => {
|
||||
expect(dataTable.getSortedColumnHeader().getText()).toBe('Deleted');
|
||||
expect(dataTable.getSortingOrder()).toBe('desc');
|
||||
});
|
||||
|
||||
it('Location column redirect - file in user Home [C217144] [C260968]', () => {
|
||||
dataTable.clickItemLocation(fileUser)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files' ]));
|
||||
});
|
||||
|
||||
it('Location column redirect - file in site [C217144] [C260969]', () => {
|
||||
dataTable.clickItemLocation(fileSite)
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName ]));
|
||||
});
|
||||
});
|
||||
});
|
244
e2e/suites/navigation/breadcrumb.test.ts
Executable file
244
e2e/suites/navigation/breadcrumb.test.ts
Executable file
@ -0,0 +1,244 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
|
||||
import { SIDEBAR_LABELS, SITE_VISIBILITY } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Breadcrumb', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const parent = `parent-${Utils.random()}`; let parentId;
|
||||
const subFolder1 = `subFolder1-${Utils.random()}`; let subFolder1Id;
|
||||
const subFolder2 = `subFolder2-${Utils.random()}`; let subFolder2Id;
|
||||
const fileName1 = `file1-${Utils.random()}.txt`;
|
||||
|
||||
const siteName = `site-${Utils.random()}`;
|
||||
|
||||
const parent2 = `parent2-${Utils.random()}`; let parent2Id;
|
||||
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
|
||||
const folder1Renamed = `renamed-${Utils.random()}`;
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { breadcrumb } = page.toolbar;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username)
|
||||
.then(() => apis.user.nodes.createFolder(parent)).then(resp => parentId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolder(subFolder1, parentId)).then(resp => subFolder1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolder(subFolder2, subFolder1Id)).then(resp => subFolder2Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(fileName1, subFolder2Id))
|
||||
|
||||
.then(() => apis.user.nodes.createFolder(parent2)).then(resp => parent2Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolder(folder1, parent2Id)).then(resp => folder1Id = resp.data.entry.id)
|
||||
|
||||
.then(() => apis.user.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC))
|
||||
.then(() => apis.user.sites.getDocLibId(siteName))
|
||||
.then(resp => apis.user.nodes.createFolder(parent, resp)).then(resp => parentId = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolder(subFolder1, parentId)).then(resp => subFolder1Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFolder(subFolder2, subFolder1Id)).then(resp => subFolder2Id = resp.data.entry.id)
|
||||
.then(() => apis.user.nodes.createFile(fileName1, subFolder2Id))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
apis.user.nodes.deleteNodeById(parentId),
|
||||
apis.user.nodes.deleteNodeById(parent2Id),
|
||||
apis.user.sites.deleteSite(siteName),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('Personal Files breadcrumb main node [C260964]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => {
|
||||
expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items');
|
||||
expect(breadcrumb.getCurrentItemName()).toBe('Personal Files');
|
||||
});
|
||||
});
|
||||
|
||||
it('File Libraries breadcrumb main node [C260966]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => {
|
||||
expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items');
|
||||
expect(breadcrumb.getCurrentItemName()).toBe('File Libraries');
|
||||
});
|
||||
});
|
||||
|
||||
it('Recent Files breadcrumb main node [C260971]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => {
|
||||
expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items');
|
||||
expect(breadcrumb.getCurrentItemName()).toBe('Recent Files');
|
||||
});
|
||||
});
|
||||
|
||||
it('Shared Files breadcrumb main node [C260972]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => {
|
||||
expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items');
|
||||
expect(breadcrumb.getCurrentItemName()).toBe('Shared Files');
|
||||
});
|
||||
});
|
||||
|
||||
it('Favorites breadcrumb main node [C260973]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => {
|
||||
expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items');
|
||||
expect(breadcrumb.getCurrentItemName()).toBe('Favorites');
|
||||
});
|
||||
});
|
||||
|
||||
it('Trash breadcrumb main node [C260974]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => {
|
||||
expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items');
|
||||
expect(breadcrumb.getCurrentItemName()).toBe('Trash');
|
||||
});
|
||||
});
|
||||
|
||||
it('Personal Files breadcrumb for a folder hierarchy [C260965]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => page.dataTable.doubleClickOnItemName(parent))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder1))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder2))
|
||||
.then(() => {
|
||||
const expectedBreadcrumb = [ 'Personal Files', parent, subFolder1, subFolder2 ];
|
||||
expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb);
|
||||
});
|
||||
});
|
||||
|
||||
it('File Libraries breadcrumb for a folder hierarchy [C260967]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => page.dataTable.doubleClickOnItemName(siteName))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(parent))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder1))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder2))
|
||||
.then(() => {
|
||||
const expectedItems = [ 'File Libraries', siteName, parent, subFolder1, subFolder2 ];
|
||||
expect(breadcrumb.getAllItems()).toEqual(expectedItems);
|
||||
});
|
||||
});
|
||||
|
||||
it('User can navigate to any location by clicking on a step from the breadcrumb [C213235]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => page.dataTable.doubleClickOnItemName(parent))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder1))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder2))
|
||||
.then(() => breadcrumb.clickItem(subFolder1))
|
||||
.then(() => {
|
||||
const expectedBreadcrumb = [ 'Personal Files', parent, subFolder1 ];
|
||||
expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb);
|
||||
});
|
||||
});
|
||||
|
||||
it('Tooltip appears on hover on a step in breadcrumb [C213237]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => page.dataTable.doubleClickOnItemName(parent))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder1))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder2))
|
||||
.then(() => {
|
||||
expect(breadcrumb.getNthItemTooltip(3)).toEqual(subFolder1);
|
||||
});
|
||||
});
|
||||
|
||||
it('Breadcrumb updates correctly when folder is renamed [C213238]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => page.dataTable.doubleClickOnItemName(parent2))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(folder1))
|
||||
.then(() => page.dataTable.wait())
|
||||
.then(() => apis.user.nodes.renameNode(folder1Id, folder1Renamed).then(done => done))
|
||||
.then(() => page.refresh())
|
||||
.then(() => page.dataTable.wait())
|
||||
.then(() => {
|
||||
expect(breadcrumb.getCurrentItemName()).toEqual(folder1Renamed);
|
||||
});
|
||||
});
|
||||
|
||||
it('Browser back navigates to previous location regardless of breadcrumb steps [C213240]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => page.dataTable.waitForHeader())
|
||||
.then(() => page.dataTable.doubleClickOnItemName(parent))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder1))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(subFolder2))
|
||||
.then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH))
|
||||
.then(() => page.dataTable.waitForEmptyState())
|
||||
.then(() => browser.navigate().back())
|
||||
.then(() => {
|
||||
const expectedBreadcrumb = [ 'Personal Files', parent, subFolder1, subFolder2 ];
|
||||
expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb);
|
||||
});
|
||||
});
|
||||
|
||||
// disabled cause of ACA-1039
|
||||
xdescribe('as admin', () => {
|
||||
const user2 = 'a_user';
|
||||
const userFolder = `userFolder-${Utils.random()}`; let userFolderId;
|
||||
const user2Api = new RepoClient(user2, user2);
|
||||
|
||||
beforeAll(done => {
|
||||
logoutPage.load()
|
||||
.then(() => apis.admin.people.createUser(user2))
|
||||
.then(() => user2Api.nodes.createFolder(userFolder).then(resp => userFolderId = resp.data.entry.id))
|
||||
.then(() => loginPage.loginWithAdmin())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
user2Api.nodes.deleteNodeById(userFolderId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it(`Breadcrumb on navigation to a user's home [C260970]`, () => {
|
||||
page.dataTable.doubleClickOnItemName('User Homes')
|
||||
.then(() => page.dataTable.doubleClickOnItemName(user2))
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', 'User Homes', user2 ]))
|
||||
.then(() => page.dataTable.doubleClickOnItemName(userFolder))
|
||||
.then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', 'User Homes', user2, userFolder ]));
|
||||
});
|
||||
});
|
||||
});
|
139
e2e/suites/navigation/sidebar.test.ts
Executable file
139
e2e/suites/navigation/sidebar.test.ts
Executable file
@ -0,0 +1,139 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
|
||||
import { APP_ROUTES, SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
|
||||
describe('Sidebar', () => {
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { sidenav } = page;
|
||||
|
||||
beforeAll(done => {
|
||||
loginPage.loginWithAdmin().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('has "Personal Files" as default', () => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
expect(sidenav.isActiveByLabel('Personal Files')).toBe(true, 'Active link');
|
||||
});
|
||||
|
||||
it('navigates to "File Libraries"', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.FILE_LIBRARIES);
|
||||
expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('navigates to "Personal Files"', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES);
|
||||
expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.PERSONAL_FILES)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('navigates to "Shared Files"', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.SHARED_FILES);
|
||||
expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.SHARED_FILES)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('navigates to "Recent Files"', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.RECENT_FILES);
|
||||
expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.RECENT_FILES)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('navigates to "Favorites"', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.FAVORITES);
|
||||
expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.FAVORITES)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('navigates to "Trash"', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => {
|
||||
expect(browser.getCurrentUrl()).toContain(APP_ROUTES.TRASHCAN);
|
||||
expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.TRASH)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('Personal Files tooltip', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => {
|
||||
expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.PERSONAL_FILES)).toContain('View your Personal Files');
|
||||
});
|
||||
});
|
||||
|
||||
it('File Libraries tooltip', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)
|
||||
.then(() => {
|
||||
expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.FILE_LIBRARIES)).toContain('Access File Libraries');
|
||||
});
|
||||
});
|
||||
|
||||
it('Shared Files tooltip', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => {
|
||||
expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.SHARED_FILES)).toContain('View files that have been shared');
|
||||
});
|
||||
});
|
||||
|
||||
it('Recent Files tooltip', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => {
|
||||
expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.RECENT_FILES)).toContain('View files you recently edited');
|
||||
});
|
||||
});
|
||||
|
||||
it('Favorites tooltip', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => {
|
||||
expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.FAVORITES)).toContain('View your favorite files and folders');
|
||||
});
|
||||
});
|
||||
|
||||
it('Trash tooltip', () => {
|
||||
sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => {
|
||||
expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.TRASH)).toContain('View deleted files in the trash');
|
||||
});
|
||||
});
|
||||
});
|
228
e2e/suites/pagination/pag-favorites.test.ts
Executable file
228
e2e/suites/pagination/pag-favorites.test.ts
Executable file
@ -0,0 +1,228 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Pagination on Favorites', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
const { nodes: nodesApi, favorites: favoritesApi } = apis.user;
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, pagination } = page;
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
const files = Array(101)
|
||||
.fill('file')
|
||||
.map((name, index): string => `${name}-${index + 1}.txt`);
|
||||
let filesIds;
|
||||
|
||||
const file = `file-${Utils.random()}.txt`; let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on empty page', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('pagination controls not displayed [C213164]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => {
|
||||
expect(pagination.range.isPresent()).toBe(false);
|
||||
expect(pagination.maxItems.isPresent()).toBe(false);
|
||||
expect(pagination.currentPage.isPresent()).toBe(false);
|
||||
expect(pagination.totalPages.isPresent()).toBe(false);
|
||||
expect(pagination.previousButton.isPresent()).toBe(false);
|
||||
expect(pagination.nextButton.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on single page', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => favoritesApi.addFavoriteById('file', fileId))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodeById(fileId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('page selector not displayed when having a single page [C213165]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on multiple pages', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFiles(files, parent)
|
||||
.then(resp => filesIds = resp.data.list.entries.map(entries => entries.entry.id))
|
||||
.then(() => favoritesApi.addFavoritesByIds('file', filesIds))
|
||||
.then(() => favoritesApi.waitForApi({ expect: 101 }))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodes([ parent ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('default values [C213157]', () => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(pagination.maxItems.getText()).toContain('25');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.totalPages.getText()).toContain('of 5');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
});
|
||||
|
||||
it('page sizes [C213157]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => {
|
||||
const [ first, second, third ] = [1, 2, 3]
|
||||
.map(nth => pagination.menu.getNthItem(nth).getText());
|
||||
expect(first).toBe('25');
|
||||
expect(second).toBe('50');
|
||||
expect(third).toBe('100');
|
||||
})
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the page size [C213158]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => pagination.menu.clickMenuItem('50'))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.maxItems)).toContain('50');
|
||||
expect(pagination.getText(pagination.totalPages)).toContain('of 3');
|
||||
})
|
||||
.then(() => pagination.openMaxItemsMenu())
|
||||
.then(() => pagination.menu.clickMenuItem('100'))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.maxItems)).toContain('100');
|
||||
expect(pagination.getText(pagination.totalPages)).toContain('of 2');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageSize());
|
||||
});
|
||||
|
||||
it('current page menu items', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => expect(pagination.menu.getItemsCount()).toBe(5))
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the current page from menu [C260518]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(3))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.range)).toContain('51-75 of 101');
|
||||
expect(pagination.getText(pagination.currentPage)).toContain('Page 3');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
expect(dataTable.getRowName('file-40.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to next page [C213160]', () => {
|
||||
pagination.nextButton.click()
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('26-50 of 101');
|
||||
expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to previous page [C213160]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(2))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => pagination.previousButton.click())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(dataTable.getRowName('file-88.txt').isPresent())
|
||||
.toBe(true, 'File not found on page');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('Previous button is disabled on first page [C260519]', () => {
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page');
|
||||
});
|
||||
|
||||
it('Next button is disabled on last page [C260519]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(5))
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 5');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
228
e2e/suites/pagination/pag-personal-files.test.ts
Executable file
228
e2e/suites/pagination/pag-personal-files.test.ts
Executable file
@ -0,0 +1,228 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Pagination on Personal Files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
const { nodes: nodesApi } = apis.user;
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, pagination } = page;
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
const files = Array(101)
|
||||
.fill('file')
|
||||
.map((name, index): string => `${name}-${index + 1}.txt`);
|
||||
|
||||
const file = `file-${Utils.random()}.txt`; let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on empty page', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('pagination controls not displayed [C213164]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => {
|
||||
expect(pagination.range.isPresent()).toBe(false);
|
||||
expect(pagination.maxItems.isPresent()).toBe(false);
|
||||
expect(pagination.currentPage.isPresent()).toBe(false);
|
||||
expect(pagination.totalPages.isPresent()).toBe(false);
|
||||
expect(pagination.previousButton.isPresent()).toBe(false);
|
||||
expect(pagination.nextButton.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on single page', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodeById(fileId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('page selector not displayed when having a single page [C213165]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on multiple pages', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFiles(files, parent)
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => dataTable.doubleClickOnItemName(parent))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodes([ parent ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('default values [C213157]', () => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(pagination.maxItems.getText()).toContain('25');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.totalPages.getText()).toContain('of 5');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
});
|
||||
|
||||
it('page sizes [C213157]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => {
|
||||
const [ first, second, third ] = [1, 2, 3]
|
||||
.map(nth => pagination.menu.getNthItem(nth).getText());
|
||||
expect(first).toBe('25');
|
||||
expect(second).toBe('50');
|
||||
expect(third).toBe('100');
|
||||
})
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the page size [C213158]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => pagination.menu.clickMenuItem('50'))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.maxItems.getText()).toContain('50');
|
||||
expect(pagination.totalPages.getText()).toContain('of 3');
|
||||
})
|
||||
.then(() => pagination.openMaxItemsMenu())
|
||||
.then(() => pagination.menu.clickMenuItem('100'))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.maxItems)).toContain('100');
|
||||
expect(pagination.getText(pagination.totalPages)).toContain('of 2');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageSize());
|
||||
});
|
||||
|
||||
it('current page menu items', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => expect(pagination.menu.getItemsCount()).toBe(5))
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the current page from menu [C260518]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(3))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('51-75 of 101');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 3');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
expect(dataTable.getRowName('file-60.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to next page [C213160]', () => {
|
||||
pagination.clickNext()
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('26-50 of 101');
|
||||
expect(dataTable.getRowName('file-30.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to previous page [C213160]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(2))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => pagination.clickPrevious())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(dataTable.getRowName('file-12.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('Previous button is disabled on first page [C260519]', () => {
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page');
|
||||
});
|
||||
|
||||
it('Next button is disabled on last page [C260519]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(5))
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 5');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
230
e2e/suites/pagination/pag-recent-files.test.ts
Executable file
230
e2e/suites/pagination/pag-recent-files.test.ts
Executable file
@ -0,0 +1,230 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Pagination on Recent Files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
const { nodes: nodesApi, search: searchApi } = apis.user;
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, pagination } = page;
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
const files = Array(101)
|
||||
.fill('file')
|
||||
.map((name, index): string => `${name}-${index + 1}.txt`);
|
||||
|
||||
const file = `file-${Utils.random()}.txt`; let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on empty page', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('pagination controls not displayed [C213164]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => {
|
||||
expect(pagination.range.isPresent()).toBe(false);
|
||||
expect(pagination.maxItems.isPresent()).toBe(false);
|
||||
expect(pagination.currentPage.isPresent()).toBe(false);
|
||||
expect(pagination.totalPages.isPresent()).toBe(false);
|
||||
expect(pagination.previousButton.isPresent()).toBe(false);
|
||||
expect(pagination.nextButton.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on single page', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => searchApi.waitForApi(username, { expect: 1 }))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodeById(fileId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('page selector not displayed when having a single page [C213165]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on multiple pages', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFiles(files, parent)
|
||||
.then(() => searchApi.waitForApi(username, { expect: 101 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodes([ parent ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('default values [C213157]', () => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(pagination.maxItems.getText()).toContain('25');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.totalPages.getText()).toContain('of 5');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
});
|
||||
|
||||
it('page sizes [C213157]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => {
|
||||
const [ first, second, third ] = [1, 2, 3]
|
||||
.map(nth => pagination.menu.getNthItem(nth).getText());
|
||||
expect(first).toBe('25');
|
||||
expect(second).toBe('50');
|
||||
expect(third).toBe('100');
|
||||
})
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the page size [C213158]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => pagination.menu.clickMenuItem('50'))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.maxItems.getText()).toContain('50');
|
||||
expect(pagination.totalPages.getText()).toContain('of 3');
|
||||
})
|
||||
.then(() => pagination.openMaxItemsMenu())
|
||||
.then(() => pagination.menu.clickMenuItem('100'))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.maxItems)).toContain('100');
|
||||
expect(pagination.getText(pagination.totalPages)).toContain('of 2');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageSize());
|
||||
});
|
||||
|
||||
it('current page menu items', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => expect(pagination.menu.getItemsCount()).toBe(5))
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the current page from menu [C260518]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(3))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('51-75 of 101');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 3');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
expect(dataTable.getRowName('file-40.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to next page [C213160]', () => {
|
||||
pagination.nextButton.click()
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('26-50 of 101');
|
||||
expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to previous page [C213160]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(2))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => pagination.previousButton.click())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(dataTable.getRowName('file-88.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('Previous button is disabled on first page [C260519]', () => {
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page');
|
||||
});
|
||||
|
||||
it('Next button is disabled on last page [C260519]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(5))
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 5');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
236
e2e/suites/pagination/pag-shared-files.test.ts
Executable file
236
e2e/suites/pagination/pag-shared-files.test.ts
Executable file
@ -0,0 +1,236 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Pagination on Shared Files', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
const { nodes: nodesApi, shared: sharedApi } = apis.user;
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, pagination } = page;
|
||||
|
||||
const parent = `parent-${Utils.random()}`;
|
||||
const files = Array(101)
|
||||
.fill('file')
|
||||
.map((name, index): string => `${name}-${index + 1}.txt`);
|
||||
let filesIds;
|
||||
|
||||
const file = `file-${Utils.random()}.txt`; let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on empty page', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('pagination controls not displayed [C213164]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => {
|
||||
expect(pagination.range.isPresent()).toBe(false);
|
||||
expect(pagination.maxItems.isPresent()).toBe(false);
|
||||
expect(pagination.currentPage.isPresent()).toBe(false);
|
||||
expect(pagination.totalPages.isPresent()).toBe(false);
|
||||
expect(pagination.previousButton.isPresent()).toBe(false);
|
||||
expect(pagination.nextButton.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on single page', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => sharedApi.shareFileById(fileId))
|
||||
.then(() => sharedApi.waitForApi({ expect: 1 }))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodeById(fileId),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('page selector not displayed when having a single page [C213165]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on multiple pages', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFiles(files, parent)
|
||||
.then(resp => filesIds = resp.data.list.entries.map(entries => entries.entry.id))
|
||||
|
||||
.then(() => sharedApi.shareFilesByIds(filesIds))
|
||||
.then(() => sharedApi.waitForApi({ expect: 101 }))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
nodesApi.deleteNodes([ parent ]),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('default values [C213157]', () => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(pagination.maxItems.getText()).toContain('25');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.totalPages.getText()).toContain('of 5');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
});
|
||||
|
||||
it('page sizes [C213157]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => {
|
||||
const [ first, second, third ] = [1, 2, 3]
|
||||
.map(nth => pagination.menu.getNthItem(nth).getText());
|
||||
expect(first).toBe('25');
|
||||
expect(second).toBe('50');
|
||||
expect(third).toBe('100');
|
||||
})
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the page size [C213158]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => pagination.menu.clickMenuItem('50'))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.maxItems.getText()).toContain('50');
|
||||
expect(pagination.totalPages.getText()).toContain('of 3');
|
||||
})
|
||||
.then(() => pagination.openMaxItemsMenu())
|
||||
.then(() => pagination.menu.clickMenuItem('100'))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.maxItems)).toContain('100');
|
||||
expect(pagination.getText(pagination.totalPages)).toContain('of 2');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageSize());
|
||||
});
|
||||
|
||||
it('current page menu items', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => expect(pagination.menu.getItemsCount()).toBe(5))
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the current page from menu [C260518]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(3))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('51-75 of 101');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 3');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
expect(dataTable.getRowName('file-40.txt').isPresent())
|
||||
.toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to next page [C213160]', () => {
|
||||
pagination.nextButton.click()
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('26-50 of 101');
|
||||
expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to previous page [C213160]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(2))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => pagination.previousButton.click())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(dataTable.getRowName('file-88.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('Previous button is disabled on first page [C260519]', () => {
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page');
|
||||
});
|
||||
|
||||
it('Next button is disabled on last page [C260519]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(5))
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 5');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
233
e2e/suites/pagination/pag-trash.test.ts
Executable file
233
e2e/suites/pagination/pag-trash.test.ts
Executable file
@ -0,0 +1,233 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { SIDEBAR_LABELS } from '../../configs';
|
||||
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
|
||||
import { Utils } from '../../utilities/utils';
|
||||
import { RepoClient } from '../../utilities/repo-client/repo-client';
|
||||
|
||||
describe('Pagination on Trash', () => {
|
||||
const username = `user-${Utils.random()}`;
|
||||
|
||||
const apis = {
|
||||
admin: new RepoClient(),
|
||||
user: new RepoClient(username, username)
|
||||
};
|
||||
const { nodes: nodesApi, trashcan: trashApi } = apis.user;
|
||||
|
||||
const loginPage = new LoginPage();
|
||||
const logoutPage = new LogoutPage();
|
||||
const page = new BrowsingPage();
|
||||
const { dataTable, pagination } = page;
|
||||
|
||||
const filesForDelete = Array(101)
|
||||
.fill('file')
|
||||
.map((name, index): string => `${name}-${index + 1}.txt`);
|
||||
let filesDeletedIds;
|
||||
|
||||
const file = `file-${Utils.random()}.txt`; let fileId;
|
||||
|
||||
beforeAll(done => {
|
||||
apis.admin.people.createUser(username).then(done);
|
||||
});
|
||||
|
||||
xit('');
|
||||
|
||||
describe('on empty page', () => {
|
||||
beforeAll(done => {
|
||||
loginPage.loginWith(username).then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
logoutPage.load().then(done);
|
||||
});
|
||||
|
||||
it('pagination controls not displayed [C213164]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => {
|
||||
expect(pagination.range.isPresent()).toBe(false);
|
||||
expect(pagination.maxItems.isPresent()).toBe(false);
|
||||
expect(pagination.currentPage.isPresent()).toBe(false);
|
||||
expect(pagination.totalPages.isPresent()).toBe(false);
|
||||
expect(pagination.previousButton.isPresent()).toBe(false);
|
||||
expect(pagination.nextButton.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on single page', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id)
|
||||
.then(() => nodesApi.deleteNodeById(fileId, false))
|
||||
.then(() => trashApi.waitForApi({ expect: 1 }))
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
trashApi.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('page selector not displayed when having a single page [C213165]', () => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('on multiple pages', () => {
|
||||
beforeAll(done => {
|
||||
nodesApi.createFiles(filesForDelete)
|
||||
.then(resp => filesDeletedIds = resp.data.list.entries.map(entries => entries.entry.id))
|
||||
.then(() => nodesApi.deleteNodesById(filesDeletedIds, false))
|
||||
.then(() => trashApi.waitForApi({expect: 101}))
|
||||
|
||||
.then(() => loginPage.loginWith(username))
|
||||
.then(done);
|
||||
});
|
||||
|
||||
beforeEach(done => {
|
||||
page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(done);
|
||||
});
|
||||
|
||||
afterEach(done => {
|
||||
browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done);
|
||||
});
|
||||
|
||||
afterAll(done => {
|
||||
Promise.all([
|
||||
trashApi.emptyTrash(),
|
||||
logoutPage.load()
|
||||
])
|
||||
.then(done);
|
||||
});
|
||||
|
||||
it('default values [C213157]', () => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(pagination.maxItems.getText()).toContain('25');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.totalPages.getText()).toContain('of 5');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
});
|
||||
|
||||
it('page sizes [C213157]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => {
|
||||
const [ first, second, third ] = [1, 2, 3]
|
||||
.map(nth => pagination.menu.getNthItem(nth).getText());
|
||||
expect(first).toBe('25');
|
||||
expect(second).toBe('50');
|
||||
expect(third).toBe('100');
|
||||
})
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the page size [C213158]', () => {
|
||||
pagination.openMaxItemsMenu()
|
||||
.then(() => pagination.menu.clickMenuItem('50'))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.maxItems.getText()).toContain('50');
|
||||
expect(pagination.totalPages.getText()).toContain('of 3');
|
||||
})
|
||||
.then(() => pagination.openMaxItemsMenu())
|
||||
.then(() => pagination.menu.clickMenuItem('100'))
|
||||
.then(() => {
|
||||
expect(pagination.getText(pagination.maxItems)).toContain('100');
|
||||
expect(pagination.getText(pagination.totalPages)).toContain('of 2');
|
||||
})
|
||||
.then(() => pagination.resetToDefaultPageSize());
|
||||
});
|
||||
|
||||
it('current page menu items', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => expect(pagination.menu.getItemsCount()).toBe(5))
|
||||
.then(() => pagination.menu.closeMenu());
|
||||
});
|
||||
|
||||
it('change the current page from menu [C260518]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(3))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('51-75 of 101');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 3');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled');
|
||||
expect(dataTable.getRowName('file-40.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to next page [C213160]', () => {
|
||||
pagination.nextButton.click()
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('26-50 of 101');
|
||||
expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('navigate to previous page [C213160]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(2))
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => pagination.previousButton.click())
|
||||
.then(() => dataTable.waitForHeader())
|
||||
.then(() => {
|
||||
expect(pagination.range.getText()).toContain('1-25 of 101');
|
||||
expect(dataTable.getRowName('file-88.txt').isPresent()).toBe(true, 'File not found on page');
|
||||
})
|
||||
|
||||
.then(() => pagination.resetToDefaultPageNumber());
|
||||
});
|
||||
|
||||
it('Previous button is disabled on first page [C260519]', () => {
|
||||
expect(pagination.currentPage.getText()).toContain('Page 1');
|
||||
expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page');
|
||||
});
|
||||
|
||||
it('Next button is disabled on last page [C260519]', () => {
|
||||
pagination.openCurrentPageMenu()
|
||||
.then(() => pagination.menu.clickNthItem(5))
|
||||
.then(() => {
|
||||
expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page');
|
||||
expect(pagination.currentPage.getText()).toContain('Page 5');
|
||||
expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
0
e2e/tsconfig.e2e.json
Normal file → Executable file
0
e2e/tsconfig.e2e.json
Normal file → Executable file
118
e2e/utilities/repo-client/apis/favorites/favorites-api.ts
Executable file
118
e2e/utilities/repo-client/apis/favorites/favorites-api.ts
Executable file
@ -0,0 +1,118 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { promise } from 'protractor';
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { NodesApi } from '../nodes/nodes-api';
|
||||
import { RepoClient } from './../../repo-client';
|
||||
import { Utils } from '../../../../utilities/utils';
|
||||
|
||||
export class FavoritesApi extends RepoApi {
|
||||
|
||||
addFavorite(api: RepoClient, nodeType: string, name: string): Promise<any> {
|
||||
return api.nodes.getNodeByPath(name)
|
||||
.then((response) => {
|
||||
const { id } = response.data.entry;
|
||||
return ([{
|
||||
target: {
|
||||
[nodeType]: {
|
||||
guid: id
|
||||
}
|
||||
}
|
||||
}]);
|
||||
})
|
||||
.then((data) => {
|
||||
return this.post(`/people/-me-/favorites`, { data });
|
||||
})
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
addFavoriteById(nodeType: 'file' | 'folder', id: string): Promise<any> {
|
||||
const data = [{
|
||||
target: {
|
||||
[nodeType]: {
|
||||
guid: id
|
||||
}
|
||||
}
|
||||
}];
|
||||
return this
|
||||
.post(`/people/-me-/favorites`, { data })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
addFavoritesByIds(nodeType: 'file' | 'folder', ids: string[]): Promise<any[]> {
|
||||
return ids.reduce((previous, current) => (
|
||||
previous.then(() => this.addFavoriteById(nodeType, current))
|
||||
), Promise.resolve());
|
||||
}
|
||||
|
||||
getFavorites(): Promise<any> {
|
||||
return this
|
||||
.get('/people/-me-/favorites')
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getFavoriteById(nodeId: string): Promise<any> {
|
||||
return this
|
||||
.get(`/people/-me-/favorites/${nodeId}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
isFavorite(nodeId: string) {
|
||||
return this.getFavorites()
|
||||
.then(resp => JSON.stringify(resp.data.list.entries).includes(nodeId));
|
||||
}
|
||||
|
||||
removeFavorite(api: RepoClient, nodeType: string, name: string): Promise<any> {
|
||||
return api.nodes.getNodeByPath(name)
|
||||
.then((response) => {
|
||||
const { id } = response.data.entry;
|
||||
return this.delete(`/people/-me-/favorites/${id}`);
|
||||
})
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
removeFavoriteById(nodeId: string) {
|
||||
return this
|
||||
.delete(`/people/-me-/favorites/${nodeId}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
waitForApi(data) {
|
||||
const favoriteFiles = () => {
|
||||
return this.getFavorites()
|
||||
.then(response => response.data.list.pagination.totalItems)
|
||||
.then(totalItems => {
|
||||
if ( totalItems < data.expect) {
|
||||
return Promise.reject(totalItems);
|
||||
} else {
|
||||
return Promise.resolve(totalItems);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Utils.retryCall(favoriteFiles);
|
||||
}
|
||||
}
|
38
e2e/utilities/repo-client/apis/nodes/node-body-create.ts
Executable file
38
e2e/utilities/repo-client/apis/nodes/node-body-create.ts
Executable file
@ -0,0 +1,38 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const NODE_TYPE_FILE = 'cm:content';
|
||||
export const NODE_TYPE_FOLDER = 'cm:folder';
|
||||
export const NODE_TITLE = 'cm:title';
|
||||
export const NODE_DESCRIPTION = 'cm:description';
|
||||
|
||||
export class NodeBodyCreate {
|
||||
constructor(
|
||||
public name: string,
|
||||
public nodeType: string,
|
||||
public relativePath: string = '/',
|
||||
public properties?: any[]
|
||||
) {}
|
||||
}
|
85
e2e/utilities/repo-client/apis/nodes/node-content-tree.ts
Executable file
85
e2e/utilities/repo-client/apis/nodes/node-content-tree.ts
Executable file
@ -0,0 +1,85 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NodeBodyCreate, NODE_TYPE_FILE, NODE_TYPE_FOLDER, NODE_TITLE, NODE_DESCRIPTION } from './node-body-create';
|
||||
|
||||
export interface NodeContentTree {
|
||||
name?: string;
|
||||
files?: string[];
|
||||
folders?: (string|NodeContentTree)[];
|
||||
title?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function flattenNodeContentTree(content: NodeContentTree, relativePath: string = '/'): NodeBodyCreate[] {
|
||||
const { name, files, folders, title, description } = content;
|
||||
let data: NodeBodyCreate[] = [];
|
||||
let properties: any;
|
||||
|
||||
properties = {
|
||||
[NODE_TITLE]: title,
|
||||
[NODE_DESCRIPTION]: description
|
||||
};
|
||||
|
||||
if (name) {
|
||||
data = data.concat([{
|
||||
nodeType: NODE_TYPE_FOLDER,
|
||||
name,
|
||||
relativePath,
|
||||
properties
|
||||
}]);
|
||||
|
||||
relativePath = (relativePath === '/')
|
||||
? `/${name}`
|
||||
: `${relativePath}/${name}`;
|
||||
}
|
||||
|
||||
if (folders) {
|
||||
const foldersData: NodeBodyCreate[] = folders
|
||||
.map((folder: (string|NodeContentTree)): NodeBodyCreate[] => {
|
||||
const folderData: NodeContentTree = (typeof folder === 'string')
|
||||
? { name: folder }
|
||||
: folder;
|
||||
|
||||
return flattenNodeContentTree(folderData, relativePath);
|
||||
})
|
||||
.reduce((nodesData: NodeBodyCreate[], folderData: NodeBodyCreate[]) => nodesData.concat(folderData), []);
|
||||
|
||||
data = data.concat(foldersData);
|
||||
}
|
||||
|
||||
if (files) {
|
||||
const filesData: NodeBodyCreate[] = files
|
||||
.map((filename: string): NodeBodyCreate => ({
|
||||
nodeType: NODE_TYPE_FILE,
|
||||
name: filename,
|
||||
relativePath
|
||||
}));
|
||||
|
||||
data = data.concat(filesData);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
182
e2e/utilities/repo-client/apis/nodes/nodes-api.ts
Executable file
182
e2e/utilities/repo-client/apis/nodes/nodes-api.ts
Executable file
@ -0,0 +1,182 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { NodeBodyCreate, NODE_TYPE_FILE, NODE_TYPE_FOLDER } from './node-body-create';
|
||||
import { NodeContentTree, flattenNodeContentTree } from './node-content-tree';
|
||||
|
||||
export class NodesApi extends RepoApi {
|
||||
// nodes
|
||||
getNodeByPath(relativePath: string = '/'): Promise<any> {
|
||||
return this
|
||||
.get(`/nodes/-my-`, { parameters: { relativePath } })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getNodeById(id: string): Promise<any> {
|
||||
return this
|
||||
.get(`/nodes/${id}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getNodeDescription(name: string, relativePath: string = '/') {
|
||||
relativePath = (relativePath === '/')
|
||||
? `${name}`
|
||||
: `${relativePath}/${name}`;
|
||||
|
||||
return this.getNodeByPath(`${relativePath}`)
|
||||
.then(response => response.data.entry.properties['cm:description']);
|
||||
}
|
||||
|
||||
deleteNodeById(id: string, permanent: boolean = true): Promise<any> {
|
||||
return this
|
||||
.delete(`/nodes/${id}?permanent=${permanent}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
deleteNodeByPath(path: string, permanent: boolean = true): Promise<any> {
|
||||
return this
|
||||
.getNodeByPath(path)
|
||||
.then((response: any): string => response.data.entry.id)
|
||||
.then((id: string): any => this.deleteNodeById(id, permanent))
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
deleteNodes(names: string[], relativePath: string = '', permanent: boolean = true): Promise<any[]> {
|
||||
return names.reduce((previous, current) => (
|
||||
previous.then(() => this.deleteNodeByPath(`${relativePath}/${current}`, permanent))
|
||||
), Promise.resolve());
|
||||
}
|
||||
|
||||
deleteNodesById(ids: string[], permanent: boolean = true): Promise<any[]> {
|
||||
return ids.reduce((previous, current) => (
|
||||
previous.then(() => this.deleteNodeById(current, permanent))
|
||||
), Promise.resolve());
|
||||
}
|
||||
|
||||
// children
|
||||
getNodeChildren(nodeId: string): Promise<any> {
|
||||
return this
|
||||
.get(`/nodes/${nodeId}/children`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createNode(nodeType: string, name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise<any> {
|
||||
const data = {
|
||||
name: name,
|
||||
nodeType: nodeType,
|
||||
properties: {
|
||||
'cm:title': title, 'cm:description': description
|
||||
}
|
||||
};
|
||||
|
||||
return this
|
||||
.post(`/nodes/${parentId}/children`, { data })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createFile(name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise<any> {
|
||||
return this.createNode('cm:content', name, parentId, title, description);
|
||||
}
|
||||
|
||||
createFolder(name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise<any> {
|
||||
return this.createNode('cm:folder', name, parentId, title, description);
|
||||
}
|
||||
|
||||
createChildren(data: NodeBodyCreate[]): Promise<any> {
|
||||
return this
|
||||
.post(`/nodes/-my-/children`, { data })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createContent(content: NodeContentTree, relativePath: string = '/'): Promise<any> {
|
||||
return this.createChildren(flattenNodeContentTree(content, relativePath));
|
||||
}
|
||||
|
||||
createFolders(names: string[], relativePath: string = '/'): Promise<any> {
|
||||
return this.createContent({ folders: names }, relativePath);
|
||||
}
|
||||
|
||||
createFiles(names: string[], relativePath: string = '/'): Promise<any> {
|
||||
return this.createContent({ files: names }, relativePath);
|
||||
}
|
||||
|
||||
// node content
|
||||
getNodeContent(nodeId: string): Promise<any> {
|
||||
return this
|
||||
.get(`/nodes/${nodeId}/content`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
editNodeContent(nodeId: string, content: string): Promise<any> {
|
||||
return this
|
||||
.put(`/nodes/${nodeId}/content`, { data: content })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
renameNode(nodeId: string, newName: string): Promise<any> {
|
||||
return this
|
||||
.put(`/nodes/${nodeId}`, { data: { name: newName } })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
// node permissions
|
||||
setGranularPermission(nodeId: string, inheritPermissions: boolean = false, username: string, role: string): Promise<any> {
|
||||
const data = {
|
||||
permissions: {
|
||||
isInheritanceEnabled: inheritPermissions,
|
||||
locallySet: [
|
||||
{
|
||||
authorityId: username,
|
||||
name: role
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return this
|
||||
.put(`/nodes/${nodeId}`, { data })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getNodePermissions(nodeId: string): Promise<any> {
|
||||
return this
|
||||
.get(`/nodes/${nodeId}?include=permissions`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
// lock node
|
||||
lockFile(nodeId: string, lockType: string = 'FULL') {
|
||||
return this
|
||||
.post(`/nodes/${nodeId}/lock?include=isLocked`, { data: { 'type': lockType } })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
unlockFile(nodeId: string) {
|
||||
return this
|
||||
.post(`/nodes/${nodeId}/unlock`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
}
|
43
e2e/utilities/repo-client/apis/people/people-api-models.ts
Executable file
43
e2e/utilities/repo-client/apis/people/people-api-models.ts
Executable file
@ -0,0 +1,43 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export class Person {
|
||||
id?: string;
|
||||
password?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
properties?: any;
|
||||
|
||||
constructor(username: string, password: string, details: Person) {
|
||||
this.id = username;
|
||||
this.password = password || username;
|
||||
this.firstName = username;
|
||||
this.lastName = username;
|
||||
this.email = `${username}@alfresco.com`;
|
||||
|
||||
Object.assign(this, details);
|
||||
}
|
||||
}
|
70
e2e/utilities/repo-client/apis/people/people-api.ts
Executable file
70
e2e/utilities/repo-client/apis/people/people-api.ts
Executable file
@ -0,0 +1,70 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { Person } from './people-api-models';
|
||||
|
||||
export class PeopleApi extends RepoApi {
|
||||
getUser(username: string) {
|
||||
return this
|
||||
.get(`/people/${username}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
updateUser(username: string, details?: Person): Promise<any> {
|
||||
if (details.id) {
|
||||
delete details.id;
|
||||
}
|
||||
|
||||
return this
|
||||
.put(`/people/${username}`, { data: details })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createUser(username: string, password?: string, details?: Person): Promise<any> {
|
||||
const person: Person = new Person(username, password, details);
|
||||
const onSuccess = (response) => response;
|
||||
const onError = (response) => {
|
||||
return (response.statusCode === 409)
|
||||
? Promise.resolve(this.updateUser(username, person))
|
||||
: Promise.reject(response);
|
||||
};
|
||||
|
||||
return this
|
||||
.post(`/people`, { data: person })
|
||||
.then(onSuccess, onError)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
disableUser(username: string): Promise<any> {
|
||||
return this.put(`/people/${username}`, { data: { enabled: false } })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
changePassword(username: string, newPassword: string) {
|
||||
return this.put(`/people/${username}`, { data: { password: newPassword } })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
}
|
71
e2e/utilities/repo-client/apis/repo-api.ts
Executable file
71
e2e/utilities/repo-client/apis/repo-api.ts
Executable file
@ -0,0 +1,71 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RestClient, RestClientArgs, RestClientResponse } from '../../rest-client/rest-client';
|
||||
import { RepoClientAuth, RepoClientConfig } from '../repo-client-models';
|
||||
|
||||
export abstract class RepoApi {
|
||||
private client: RestClient;
|
||||
private defaults: RepoClientConfig = new RepoClientConfig();
|
||||
|
||||
constructor(
|
||||
auth: RepoClientAuth = new RepoClientAuth(),
|
||||
private config?: RepoClientConfig
|
||||
) {
|
||||
const { username, password } = auth;
|
||||
|
||||
this.client = new RestClient(username, password);
|
||||
}
|
||||
|
||||
private createEndpointUri(endpoint: string, apiDefinition: string = 'alfresco'): string {
|
||||
const { defaults, config } = this;
|
||||
const { host, tenant } = Object.assign(defaults, config);
|
||||
|
||||
return `${host}/alfresco/api/${tenant}/public/${apiDefinition}/versions/1${endpoint}`;
|
||||
}
|
||||
|
||||
protected handleError(response: RestClientResponse) {
|
||||
const { request: { method, path, data }, data: error } = response;
|
||||
|
||||
console.log(`ERROR on ${method}\n${path}\n${data}`);
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
protected get(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') {
|
||||
return this.client.get(this.createEndpointUri(endpoint, apiDefinition), args);
|
||||
}
|
||||
|
||||
protected post(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') {
|
||||
return this.client.post(this.createEndpointUri(endpoint, apiDefinition), args);
|
||||
}
|
||||
|
||||
protected put(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') {
|
||||
return this.client.put(this.createEndpointUri(endpoint, apiDefinition), args);
|
||||
}
|
||||
|
||||
protected delete(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') {
|
||||
return this.client.delete(this.createEndpointUri(endpoint, apiDefinition), args);
|
||||
}
|
||||
}
|
71
e2e/utilities/repo-client/apis/search/search-api.ts
Executable file
71
e2e/utilities/repo-client/apis/search/search-api.ts
Executable file
@ -0,0 +1,71 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { Utils } from '../../../../utilities/utils';
|
||||
|
||||
export class SearchApi extends RepoApi {
|
||||
apiDefinition = 'search';
|
||||
|
||||
search(data: any[]): Promise<any> {
|
||||
return this
|
||||
.post(`/search`, { data }, this.apiDefinition)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
queryRecentFiles(username: string): Promise<any> {
|
||||
const data = {
|
||||
query: {
|
||||
query: '*',
|
||||
language: 'afts'
|
||||
},
|
||||
filterQueries: [
|
||||
{ query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` },
|
||||
{ query: `cm:modifier:${username} OR cm:creator:${username}` },
|
||||
{ query: `TYPE:"content" AND -TYPE:"app:filelink" AND -TYPE:"fm:post"` }
|
||||
]
|
||||
};
|
||||
|
||||
return this
|
||||
.post(`/search`, { data }, this.apiDefinition)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
waitForApi(username, data) {
|
||||
const recentFiles = () => {
|
||||
return this.queryRecentFiles(username)
|
||||
.then(response => response.data.list.pagination.totalItems)
|
||||
.then(totalItems => {
|
||||
if ( totalItems < data.expect) {
|
||||
return Promise.reject(totalItems);
|
||||
} else {
|
||||
return Promise.resolve(totalItems);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Utils.retryCall(recentFiles);
|
||||
}
|
||||
}
|
79
e2e/utilities/repo-client/apis/shared-links/shared-links-api.ts
Executable file
79
e2e/utilities/repo-client/apis/shared-links/shared-links-api.ts
Executable file
@ -0,0 +1,79 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { NodesApi } from '../nodes/nodes-api';
|
||||
import { RepoClient } from './../../repo-client';
|
||||
import { Utils } from '../../../../utilities/utils';
|
||||
|
||||
export class SharedLinksApi extends RepoApi {
|
||||
|
||||
shareFileById(id: string): Promise<any> {
|
||||
const data = [{ nodeId: id }];
|
||||
|
||||
return this.post(`/shared-links`, { data })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
shareFilesByIds(ids: string[]): Promise<any[]> {
|
||||
return ids.reduce((previous, current) => (
|
||||
previous.then(() => this.shareFileById(current))
|
||||
), Promise.resolve());
|
||||
}
|
||||
|
||||
getSharedIdOfNode(name: string) {
|
||||
return this.getSharedLinks()
|
||||
.then(resp => resp.data.list.entries.find(entries => entries.entry.name === name))
|
||||
.then(resp => resp.entry.id)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
unshareFile(name: string) {
|
||||
return this.getSharedIdOfNode(name)
|
||||
.then(id => this.delete(`/shared-links/${id}`))
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getSharedLinks(): Promise<any> {
|
||||
return this.get(`/shared-links`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
waitForApi(data) {
|
||||
const sharedFiles = () => {
|
||||
return this.getSharedLinks()
|
||||
.then(response => response.data.list.pagination.totalItems)
|
||||
.then(totalItems => {
|
||||
if ( totalItems < data.expect) {
|
||||
return Promise.reject(totalItems);
|
||||
} else {
|
||||
return Promise.resolve(totalItems);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Utils.retryCall(sharedFiles);
|
||||
}
|
||||
}
|
42
e2e/utilities/repo-client/apis/sites/sites-api-models.ts
Executable file
42
e2e/utilities/repo-client/apis/sites/sites-api-models.ts
Executable file
@ -0,0 +1,42 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { SITE_VISIBILITY } from '../../../../configs';
|
||||
|
||||
export class Site {
|
||||
title?: string;
|
||||
visibility?: string = SITE_VISIBILITY.PUBLIC;
|
||||
id?: string;
|
||||
description?: string;
|
||||
|
||||
constructor(title: string, visibility: string, details: Site) {
|
||||
this.title = title;
|
||||
this.visibility = visibility;
|
||||
this.id = title;
|
||||
this.description = `${title} description`;
|
||||
|
||||
Object.assign(this, details);
|
||||
}
|
||||
}
|
124
e2e/utilities/repo-client/apis/sites/sites-api.ts
Executable file
124
e2e/utilities/repo-client/apis/sites/sites-api.ts
Executable file
@ -0,0 +1,124 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { Site } from './sites-api-models';
|
||||
|
||||
export class SitesApi extends RepoApi {
|
||||
getSite(id: string): Promise<any> {
|
||||
return this
|
||||
.get(`/sites/${id}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getSiteContainers(siteId: string): Promise<any> {
|
||||
return this
|
||||
.get(`/sites/${siteId}/containers`)
|
||||
.then(resp => resp.data.list.entries)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getDocLibId(siteId: string) {
|
||||
return this.getSiteContainers(siteId)
|
||||
.then(resp => resp[0].entry.id)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
updateSite(id: string, details?: Site): Promise<any> {
|
||||
if (details.id) {
|
||||
delete details.id;
|
||||
}
|
||||
|
||||
return this
|
||||
.put(`/sites/${id}`, { data: details })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createOrUpdateSite(title: string, visibility: string, details?: Site): Promise<any> {
|
||||
const site: Site = new Site(title, visibility, details);
|
||||
const onSuccess = (response) => response;
|
||||
const onError = (response) => {
|
||||
return (response.statusCode === 409)
|
||||
? Promise.resolve(this.updateSite(site.id, site))
|
||||
: Promise.reject(response);
|
||||
};
|
||||
|
||||
return this
|
||||
.post(`/sites`, { data: site })
|
||||
.then(onSuccess, onError)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createSite(title: string, visibility: string, details?: Site): Promise<any> {
|
||||
const site: Site = new Site(title, visibility, details);
|
||||
return this
|
||||
.post(`/sites`, { data: site })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
createSites(titles: string[], visibility: string): Promise<any[]> {
|
||||
return titles.reduce((previous, current) => (
|
||||
previous.then(() => this.createSite(current, visibility))
|
||||
), Promise.resolve());
|
||||
}
|
||||
|
||||
deleteSite(id: string, permanent: boolean = true): Promise<any> {
|
||||
return this
|
||||
.delete(`/sites/${id}?permanent=${permanent}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
deleteSites(ids: string[], permanent: boolean = true): Promise<any[]> {
|
||||
return ids.reduce((previous, current) => (
|
||||
previous.then(() => this.deleteSite(current))
|
||||
), Promise.resolve());
|
||||
}
|
||||
|
||||
updateSiteMember(siteId: string, userId: string, role: string): Promise<any> {
|
||||
return this
|
||||
.put(`/sites/${siteId}/members/${userId}`, { data: { role } })
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
addSiteMember(siteId: string, userId: string, role: string): Promise<any> {
|
||||
const onSuccess = (response) => response;
|
||||
const onError = (response) => {
|
||||
return (response.statusCode === 409)
|
||||
? Promise.resolve(this.updateSiteMember(siteId, userId, role))
|
||||
: Promise.reject(response);
|
||||
};
|
||||
|
||||
return this
|
||||
.post(`/sites/${siteId}/members`, { data: { role, id: userId } })
|
||||
.then(onSuccess, onError)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
deleteSiteMember(siteId: string, userId: string): Promise<any> {
|
||||
return this
|
||||
.delete(`/sites/${siteId}/members/${userId}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
}
|
76
e2e/utilities/repo-client/apis/trashcan/trashcan-api.ts
Executable file
76
e2e/utilities/repo-client/apis/trashcan/trashcan-api.ts
Executable file
@ -0,0 +1,76 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoApi } from '../repo-api';
|
||||
import { Utils } from '../../../../utilities/utils';
|
||||
|
||||
export class TrashcanApi extends RepoApi {
|
||||
permanentlyDelete(id: string): Promise<any> {
|
||||
return this
|
||||
.delete(`/deleted-nodes/${id}`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
restore(id: string) {
|
||||
return this
|
||||
.post(`/deleted-nodes/${id}/restore`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
getDeletedNodes(): Promise<any> {
|
||||
return this
|
||||
.get(`/deleted-nodes?maxItems=1000`)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
emptyTrash(): Promise<any> {
|
||||
return this.getDeletedNodes()
|
||||
.then(resp => {
|
||||
return resp.data.list.entries.map(entries => entries.entry.id);
|
||||
})
|
||||
.then(ids => {
|
||||
return ids.reduce((previous, current) => (
|
||||
previous.then(() => this.permanentlyDelete(current))
|
||||
), Promise.resolve());
|
||||
})
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
waitForApi(data) {
|
||||
const deletedFiles = () => {
|
||||
return this.getDeletedNodes()
|
||||
.then(response => response.data.list.pagination.totalItems)
|
||||
.then(totalItems => {
|
||||
if ( totalItems < data.expect) {
|
||||
return Promise.reject(totalItems);
|
||||
} else {
|
||||
return Promise.resolve(totalItems);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Utils.retryCall(deletedFiles);
|
||||
}
|
||||
}
|
46
e2e/utilities/repo-client/repo-client-models.ts
Executable file
46
e2e/utilities/repo-client/repo-client-models.ts
Executable file
@ -0,0 +1,46 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ADMIN_USERNAME,
|
||||
ADMIN_PASSWORD,
|
||||
REPO_API_HOST,
|
||||
REPO_API_TENANT
|
||||
} from '../../configs';
|
||||
|
||||
export class RepoClientAuth {
|
||||
static DEFAULT_USERNAME: string = ADMIN_USERNAME;
|
||||
static DEFAULT_PASSWORD: string = ADMIN_PASSWORD;
|
||||
|
||||
constructor(
|
||||
public username: string = RepoClientAuth.DEFAULT_USERNAME,
|
||||
public password: string = RepoClientAuth.DEFAULT_PASSWORD
|
||||
) {}
|
||||
}
|
||||
|
||||
export class RepoClientConfig {
|
||||
host?: string = REPO_API_HOST;
|
||||
tenant?: string = REPO_API_TENANT;
|
||||
}
|
59
e2e/utilities/repo-client/repo-client.ts
Executable file
59
e2e/utilities/repo-client/repo-client.ts
Executable file
@ -0,0 +1,59 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RepoClientAuth, RepoClientConfig } from './repo-client-models';
|
||||
|
||||
import { PeopleApi } from './apis/people/people-api';
|
||||
import { NodesApi } from './apis/nodes/nodes-api';
|
||||
import { SitesApi } from './apis/sites/sites-api';
|
||||
import { FavoritesApi } from './apis/favorites/favorites-api';
|
||||
import { SharedLinksApi } from './apis/shared-links/shared-links-api';
|
||||
import { TrashcanApi } from './apis/trashcan/trashcan-api';
|
||||
import { SearchApi } from './apis/search/search-api';
|
||||
|
||||
export class RepoClient {
|
||||
public people: PeopleApi = new PeopleApi(this.auth, this.config);
|
||||
public nodes: NodesApi = new NodesApi(this.auth, this.config);
|
||||
public sites: SitesApi = new SitesApi(this.auth, this.config);
|
||||
public favorites: FavoritesApi = new FavoritesApi(this.auth, this.config);
|
||||
public shared: SharedLinksApi = new SharedLinksApi(this.auth, this.config);
|
||||
public trashcan: TrashcanApi = new TrashcanApi(this.auth, this.config);
|
||||
public search: SearchApi = new SearchApi(this.auth, this.config);
|
||||
|
||||
constructor(
|
||||
private username: string = RepoClientAuth.DEFAULT_USERNAME,
|
||||
private password: string = RepoClientAuth.DEFAULT_PASSWORD,
|
||||
private config?: RepoClientConfig
|
||||
) {}
|
||||
|
||||
private get auth(): RepoClientAuth {
|
||||
const { username, password } = this;
|
||||
return { username, password };
|
||||
}
|
||||
}
|
||||
|
||||
export * from './apis/nodes/node-body-create';
|
||||
export * from './apis/nodes/node-content-tree';
|
||||
export * from './apis/nodes/nodes-api';
|
79
e2e/utilities/reporters/console/console-logger.ts
Executable file
79
e2e/utilities/reporters/console/console-logger.ts
Executable file
@ -0,0 +1,79 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
const chalk = require('chalk');
|
||||
/* tslint:enable */
|
||||
|
||||
export const log = {
|
||||
i: 0,
|
||||
|
||||
get indentation(): string {
|
||||
return new Array(this.i).fill(' ').join('');
|
||||
},
|
||||
|
||||
indent() {
|
||||
this.i++;
|
||||
return this;
|
||||
},
|
||||
|
||||
unindent() {
|
||||
this.i--;
|
||||
return this;
|
||||
},
|
||||
|
||||
log(message: string = '', options: any = { ignoreIndentation: false }) {
|
||||
const indentation = (!options.ignoreIndentation)
|
||||
? this.indentation
|
||||
: '';
|
||||
|
||||
console.log(`${indentation}${message}`);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
blank() {
|
||||
return this.log();
|
||||
},
|
||||
|
||||
info(message: string = '', options: any = { bold: false, title: false }) {
|
||||
const { bold } = options;
|
||||
const style = (bold ? chalk.bold : chalk).gray;
|
||||
|
||||
return this.log(style(message), options);
|
||||
},
|
||||
|
||||
success(message: string = '', options: any = { bold: false }) {
|
||||
const style = options.bold ? chalk.bold.green : chalk.green;
|
||||
|
||||
return this.log(style(message), options);
|
||||
},
|
||||
|
||||
error(message: string = '', options: any = { bold: false }) {
|
||||
const style = options.bold ? chalk.bold.red : chalk.red;
|
||||
|
||||
return this.log(style(message), options);
|
||||
}
|
||||
};
|
90
e2e/utilities/reporters/console/console.ts
Executable file
90
e2e/utilities/reporters/console/console.ts
Executable file
@ -0,0 +1,90 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { log } from './console-logger';
|
||||
|
||||
const errors = [];
|
||||
|
||||
export const consoleReporter = {
|
||||
jasmineStarted(suiteInfo) {
|
||||
log.blank().info(
|
||||
`Running ${suiteInfo.totalSpecsDefined} tests`,
|
||||
{ bold: true, title: true }
|
||||
).blank();
|
||||
},
|
||||
|
||||
suiteStarted(suite) {
|
||||
log.info(suite.description).indent();
|
||||
},
|
||||
|
||||
specDone: (spec) => {
|
||||
const {
|
||||
status,
|
||||
description,
|
||||
failedExpectations
|
||||
} = spec;
|
||||
|
||||
if (status === 'passed') {
|
||||
log.success(`∙ ${description}`);
|
||||
}
|
||||
|
||||
if (status === 'failed') {
|
||||
log.error(`✕ ${description}`, { bold: true });
|
||||
|
||||
errors.push(spec);
|
||||
|
||||
failedExpectations.forEach((failed) => {
|
||||
log.error(` ${failed.message}`);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
suiteDone: (result) => {
|
||||
log.unindent();
|
||||
},
|
||||
|
||||
jasmineDone: (result) => {
|
||||
if (!!errors.length) {
|
||||
log .blank()
|
||||
.blank()
|
||||
.info(`${errors.length} failing tests`, { bold: true, title: true });
|
||||
|
||||
errors.forEach(error => {
|
||||
log .blank()
|
||||
.error(`✕ ${error.fullName}`, { bold: true });
|
||||
|
||||
error.failedExpectations.forEach(failed => {
|
||||
log .info(`${failed.message}`)
|
||||
.blank()
|
||||
.error(`${failed.stack}`);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
log.success(`All tests passed!`, { bold: true });
|
||||
}
|
||||
|
||||
log.blank().blank();
|
||||
}
|
||||
};
|
63
e2e/utilities/rest-client/rest-client-models.ts
Executable file
63
e2e/utilities/rest-client/rest-client-models.ts
Executable file
@ -0,0 +1,63 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
interface RequestConfig {
|
||||
timeout?: number;
|
||||
noDelay?: boolean;
|
||||
keepAlive?: boolean;
|
||||
keepAliveDelay?: number;
|
||||
}
|
||||
|
||||
interface ResponseConfig {
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
interface ResponseRequest {
|
||||
method: string;
|
||||
path: string;
|
||||
data: string;
|
||||
}
|
||||
|
||||
export interface NodeRestClient {
|
||||
get(uri: string, callback: Function): Function;
|
||||
post(uri: string, callback: Function): Function;
|
||||
put(uri: string, callback: Function): Function;
|
||||
delete(uri: string, callback: Function): Function;
|
||||
}
|
||||
|
||||
export interface RestClientArgs {
|
||||
data?: any;
|
||||
parameters?: any;
|
||||
headers?: any;
|
||||
requestConfig?: RequestConfig;
|
||||
responseConfig?: ResponseConfig;
|
||||
}
|
||||
|
||||
export interface RestClientResponse {
|
||||
request: ResponseRequest;
|
||||
data: any;
|
||||
statusMessage: string;
|
||||
statusCode: number;
|
||||
}
|
89
e2e/utilities/rest-client/rest-client.ts
Executable file
89
e2e/utilities/rest-client/rest-client.ts
Executable file
@ -0,0 +1,89 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Client } from 'node-rest-client';
|
||||
import { NodeRestClient, RestClientArgs, RestClientResponse } from './rest-client-models';
|
||||
|
||||
export * from './rest-client-models';
|
||||
|
||||
export class RestClient {
|
||||
private static DEFAULT_HEADERS = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
};
|
||||
|
||||
private client: NodeRestClient;
|
||||
|
||||
constructor(user: string, password: string) {
|
||||
this.client = <NodeRestClient>(new Client({ user, password }));
|
||||
}
|
||||
|
||||
get(uri: string, args: RestClientArgs = {}): Promise<RestClientResponse> {
|
||||
return this.promisify('get', uri, args);
|
||||
}
|
||||
|
||||
post(uri: string, args: RestClientArgs = {}): Promise<RestClientResponse> {
|
||||
return this.promisify('post', uri, args);
|
||||
}
|
||||
|
||||
put(uri: string, args: RestClientArgs = {}): Promise<RestClientResponse> {
|
||||
return this.promisify('put', uri, args);
|
||||
}
|
||||
|
||||
delete(uri: string, args: RestClientArgs = {}): Promise<RestClientResponse> {
|
||||
return this.promisify('delete', uri, args);
|
||||
}
|
||||
|
||||
private createArgs(args: RestClientArgs = {}): RestClientArgs {
|
||||
const data = JSON.stringify(args.data);
|
||||
|
||||
return Object.assign({}, RestClient.DEFAULT_HEADERS, args, { data });
|
||||
}
|
||||
|
||||
private promisify(fnName: string, uri: string, args: RestClientArgs): Promise<RestClientResponse> {
|
||||
const fn: Function = this.client[fnName];
|
||||
const fnArgs = [ encodeURI(uri), this.createArgs(args) ];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const fnCallback = (data, rawResponse) => {
|
||||
const {
|
||||
statusCode, statusMessage,
|
||||
req: { method, path }
|
||||
} = rawResponse;
|
||||
|
||||
const response: RestClientResponse = {
|
||||
data, statusCode, statusMessage,
|
||||
request: { method, path, data: args.data }
|
||||
};
|
||||
|
||||
(response.statusCode >= 400)
|
||||
? reject(response)
|
||||
: resolve(response);
|
||||
};
|
||||
|
||||
fn(...fnArgs, fnCallback);
|
||||
});
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user