mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-4552][ADF-4482] Social component refactoring, add ability to unRate, added e2e automation (#4749)
* [ADF-4552] Rating component refactoring, add ability to unRate * [ADF-4552] RTL support added * [ADF-4552] Improve behaviour and styling structure in RTL languages * [ADF-4552] Improve behaviour and styling structure in RTL languages * [ADF-4552] Added refresh rating when the node Id input changes * [ADF-4552][ADF-4482] Refactor social component, add ability to unrate, add e2e automation * [ADF-4552][ADF-4482] Added unsibscribe from Observables, added css variables, removed unused class id's * [ADF-4552][ADF-4482] Improve structure and behaviour of e2e automation tests * [ADF-4552][ADF-4482] Improve structure and behaviour of e2e automation tests * [ADF-4552][ADF-4482] fix expected single space * [ADF-4552][ADF-4482] fix lint check failure * Fix circular dependency error
This commit is contained in:
committed by
Eugenio Romano
parent
b19646d201
commit
3d67d9dc75
@@ -7,10 +7,18 @@ Last reviewed: 2019-01-14
|
|||||||
|
|
||||||
# [Rating component](../../../lib/content-services/social/rating.component.ts "Defined in rating.component.ts")
|
# [Rating component](../../../lib/content-services/social/rating.component.ts "Defined in rating.component.ts")
|
||||||
|
|
||||||
Allows a user to add ratings to an item.
|
Allows a user to add and remove rating to an item.
|
||||||
|
It displays the average rating and the number of ratings. If the user has not rated the item the average rating stars color is grey.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
If the user has rated the item the average rating stars color is yellow.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
In order to remove the rating the user should click on the same star that he rated.
|
||||||
|
If the average is decimal number it will be rounded.
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@@ -31,7 +39,7 @@ Allows a user to add ratings to an item.
|
|||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| changeVote | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<Object>` | Emitted when the "vote" gets changed. |
|
| changeVote | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<Object>` | Average rating is emitted when the "vote" gets changed. |
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 9.9 KiB |
BIN
docs/docassets/images/social3.png
Normal file
BIN
docs/docassets/images/social3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
209
e2e/content-services/social/social.component.e2e.ts
Normal file
209
e2e/content-services/social/social.component.e2e.ts
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { LoginPage, LikePage, RatePage } from '@alfresco/adf-testing';
|
||||||
|
import { AlfrescoApiCompatibility as AlfrescoApi } from '@alfresco/js-api';
|
||||||
|
import { AcsUserModel } from '../../models/ACS/acsUserModel';
|
||||||
|
import { FileModel } from '../../models/ACS/fileModel';
|
||||||
|
import resources = require('../../util/resources');
|
||||||
|
import { UploadActions } from '../../actions/ACS/upload.actions';
|
||||||
|
import { NavigationBarPage } from '../../pages/adf/navigationBarPage';
|
||||||
|
import { SocialPage } from '../../pages/adf/demo-shell/socialPage';
|
||||||
|
import { browser } from 'protractor';
|
||||||
|
|
||||||
|
describe('Social component', () => {
|
||||||
|
|
||||||
|
const loginPage = new LoginPage();
|
||||||
|
const likePage = new LikePage();
|
||||||
|
const ratePage = new RatePage();
|
||||||
|
const socialPage = new SocialPage();
|
||||||
|
const navigationBarPage = new NavigationBarPage();
|
||||||
|
const componentOwner = new AcsUserModel();
|
||||||
|
const componentVisitor = new AcsUserModel();
|
||||||
|
const secondComponentVisitor = new AcsUserModel();
|
||||||
|
const uploadActions = new UploadActions();
|
||||||
|
|
||||||
|
const blueLikeColor = ('rgba(33, 150, 243, 1)');
|
||||||
|
const greyLikeColor = ('rgba(128, 128, 128, 1)');
|
||||||
|
const yellowRatedStarColor = ('rgba(255, 233, 68, 1)');
|
||||||
|
const averageStarColor = ('rgba(128, 128, 128, 1)');
|
||||||
|
|
||||||
|
let emptyFile;
|
||||||
|
|
||||||
|
const emptyFileModel = new FileModel({
|
||||||
|
'name': resources.Files.ADF_DOCUMENTS.TXT_0B.file_name,
|
||||||
|
'location': resources.Files.ADF_DOCUMENTS.TXT_0B.file_location
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
this.alfrescoJsApi = new AlfrescoApi({
|
||||||
|
provider: 'ECM',
|
||||||
|
hostEcm: browser.params.testConfig.adf.url
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.alfrescoJsApi.login(browser.params.testConfig.adf.adminEmail, browser.params.testConfig.adf.adminPassword);
|
||||||
|
|
||||||
|
await this.alfrescoJsApi.core.peopleApi.addPerson(componentOwner);
|
||||||
|
|
||||||
|
await this.alfrescoJsApi.core.peopleApi.addPerson(componentVisitor);
|
||||||
|
|
||||||
|
await this.alfrescoJsApi.core.peopleApi.addPerson(secondComponentVisitor);
|
||||||
|
|
||||||
|
await this.alfrescoJsApi.login(componentOwner.id, componentOwner.password);
|
||||||
|
|
||||||
|
emptyFile = await uploadActions.uploadFile(this.alfrescoJsApi, emptyFileModel.location, emptyFileModel.name, '-my-');
|
||||||
|
|
||||||
|
await this.alfrescoJsApi.core.nodesApi.updateNode(emptyFile.entry.id,
|
||||||
|
|
||||||
|
{
|
||||||
|
permissions: {
|
||||||
|
locallySet: [{
|
||||||
|
authorityId: componentVisitor.getId(),
|
||||||
|
name: 'Consumer',
|
||||||
|
accessStatus: 'ALLOWED'
|
||||||
|
}, {
|
||||||
|
authorityId: secondComponentVisitor.getId(),
|
||||||
|
name: 'Consumer',
|
||||||
|
accessStatus: 'ALLOWED'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async (done) => {
|
||||||
|
await uploadActions.deleteFilesOrFolder(this.alfrescoJsApi, emptyFile.entry.id);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('User interaction on their own components', () => {
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await loginPage.loginToContentServicesUsingUserModel(componentOwner);
|
||||||
|
await navigationBarPage.clickSocialButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('[C203006] Should be able to like and unlike their components but not rate them,', () => {
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(socialPage.getNodeIdFieldValue()).toEqual(emptyFile.entry.id);
|
||||||
|
likePage.clickLike();
|
||||||
|
expect(likePage.getLikeCounter()).toBe('1');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getLikedIconColor()).toBe(blueLikeColor);
|
||||||
|
ratePage.rateComponent(4);
|
||||||
|
expect(ratePage.getRatingCounter()).toBe('0');
|
||||||
|
expect(ratePage.isNotStarRated(4));
|
||||||
|
expect(ratePage.getUnratedStarColor(4)).toBe(averageStarColor);
|
||||||
|
likePage.clickUnlike();
|
||||||
|
expect(likePage.getLikeCounter()).toBe('0');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getUnLikedIconColor()).toBe(greyLikeColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('User interaction on components that belong to other users', () => {
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await loginPage.loginToContentServicesUsingUserModel(componentVisitor);
|
||||||
|
await navigationBarPage.clickSocialButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('[C260324] Should be able to like and unlike a component', () => {
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(socialPage.getNodeIdFieldValue()).toEqual(emptyFile.entry.id);
|
||||||
|
expect(likePage.getLikeCounter()).toEqual('0');
|
||||||
|
expect(likePage.getUnLikedIconColor()).toBe(greyLikeColor);
|
||||||
|
likePage.clickLike();
|
||||||
|
expect(likePage.getLikeCounter()).toBe('1');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getLikedIconColor()).toBe(blueLikeColor);
|
||||||
|
likePage.clickUnlike();
|
||||||
|
expect(likePage.getLikeCounter()).toBe('0');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getUnLikedIconColor()).toBe(greyLikeColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('[C310198] Should be able to rate and unRate a component', () => {
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(socialPage.getNodeIdFieldValue()).toEqual(emptyFile.entry.id);
|
||||||
|
expect(ratePage.getRatingCounter()).toBe('0');
|
||||||
|
ratePage.rateComponent(4);
|
||||||
|
expect(ratePage.getRatingCounter()).toBe('1');
|
||||||
|
expect(ratePage.isStarRated(4));
|
||||||
|
expect(ratePage.getRatedStarColor(4)).toBe(yellowRatedStarColor);
|
||||||
|
ratePage.removeRating(4);
|
||||||
|
expect(ratePage.getRatingCounter()).toBe('0');
|
||||||
|
expect(ratePage.isNotStarRated(4));
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Multiple Users interaction', () => {
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await loginPage.loginToContentServicesUsingUserModel(componentVisitor);
|
||||||
|
await navigationBarPage.clickSocialButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('[C310197] Should be able to like, unLike, display total likes', async () => {
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(socialPage.getNodeIdFieldValue()).toEqual(emptyFile.entry.id);
|
||||||
|
expect(likePage.getUnLikedIconColor()).toBe(greyLikeColor);
|
||||||
|
likePage.clickLike();
|
||||||
|
expect(likePage.getLikeCounter()).toBe('1');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getLikedIconColor()).toBe(blueLikeColor);
|
||||||
|
|
||||||
|
await loginPage.loginToContentServicesUsingUserModel(secondComponentVisitor);
|
||||||
|
navigationBarPage.clickSocialButton();
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(likePage.getUnLikedIconColor()).toBe(greyLikeColor);
|
||||||
|
likePage.clickLike();
|
||||||
|
expect(likePage.getLikeCounter()).toEqual('2');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getLikedIconColor()).toBe(blueLikeColor);
|
||||||
|
likePage.clickUnlike();
|
||||||
|
expect(likePage.getLikeCounter()).toEqual('1');
|
||||||
|
likePage.removeHoverFromLikeButton();
|
||||||
|
expect(likePage.getUnLikedIconColor()).toBe(greyLikeColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('[C260327] Should be able to rate, unRate, display total ratings, display average rating', async () => {
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(socialPage.getNodeIdFieldValue()).toEqual(emptyFile.entry.id);
|
||||||
|
ratePage.rateComponent(4);
|
||||||
|
expect(ratePage.getRatingCounter()).toEqual('1');
|
||||||
|
expect(ratePage.isStarRated(4));
|
||||||
|
expect(ratePage.getRatedStarColor(4)).toBe(yellowRatedStarColor);
|
||||||
|
|
||||||
|
await loginPage.loginToContentServicesUsingUserModel(secondComponentVisitor);
|
||||||
|
navigationBarPage.clickSocialButton();
|
||||||
|
socialPage.writeCustomNodeId(emptyFile.entry.id);
|
||||||
|
expect(socialPage.getNodeIdFieldValue()).toEqual(emptyFile.entry.id);
|
||||||
|
expect(ratePage.getRatingCounter()).toEqual('1');
|
||||||
|
expect(ratePage.getAverageStarColor(4)).toBe(averageStarColor);
|
||||||
|
ratePage.rateComponent(0);
|
||||||
|
expect(ratePage.getRatingCounter()).toEqual('2');
|
||||||
|
expect(ratePage.isStarRated(2));
|
||||||
|
ratePage.removeRating(0);
|
||||||
|
expect(ratePage.getRatingCounter()).toEqual('1');
|
||||||
|
expect(ratePage.getAverageStarColor(4)).toBe(averageStarColor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
34
e2e/pages/adf/demo-shell/socialPage.ts
Normal file
34
e2e/pages/adf/demo-shell/socialPage.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { by, element } from 'protractor';
|
||||||
|
import { BrowserActions, BrowserVisibility } from '@alfresco/adf-testing';
|
||||||
|
|
||||||
|
export class SocialPage {
|
||||||
|
|
||||||
|
nodeIdField = element(by.css(`input[id="nodeId"]`));
|
||||||
|
|
||||||
|
getNodeIdFieldValue() {
|
||||||
|
BrowserVisibility.waitUntilElementIsVisible(this.nodeIdField);
|
||||||
|
return this.nodeIdField.getAttribute('value');
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCustomNodeId(nodeId: string) {
|
||||||
|
return BrowserActions.clearSendKeys(this.nodeIdField, nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -47,6 +47,10 @@ export class NavigationBarPage {
|
|||||||
BrowserActions.clickExecuteScript(`.adf-sidenav-link[data-automation-id="${title}"]`);
|
BrowserActions.clickExecuteScript(`.adf-sidenav-link[data-automation-id="${title}"]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clickSocialButton() {
|
||||||
|
this.clickMenuButton('Social');
|
||||||
|
}
|
||||||
|
|
||||||
async clickTagButton() {
|
async clickTagButton() {
|
||||||
this.clickMenuButton('Tag');
|
this.clickMenuButton('Tag');
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,9 @@
|
|||||||
<mat-icon>thumb_up</mat-icon>
|
<mat-icon>thumb_up</mat-icon>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="adf-like-counter-container">
|
||||||
<div id="adf-like-counter" class="adf-like-counter">{{likesCounter}}</div>
|
<div id="adf-like-counter" class="adf-like-counter">{{likesCounter}}</div>
|
||||||
<div class="adf-left" *ngIf="likesCounter<=1">Like</div>
|
<div class="adf-left" *ngIf="likesCounter<=1">Like</div>
|
||||||
<div class="adf-left" *ngIf="likesCounter>1">Likes</div>
|
<div class="adf-left" *ngIf="likesCounter>1">Likes</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,42 +1,41 @@
|
|||||||
|
@mixin selected {
|
||||||
|
color: #2196f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin unselected {
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
.adf-like-container {
|
.adf-like-container {
|
||||||
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 13px;
|
||||||
|
|
||||||
.adf-like {
|
.adf-like-counter-container {
|
||||||
padding: 5px;
|
display: inherit;
|
||||||
cursor: pointer;
|
padding: 0 6px;
|
||||||
float: left;
|
}
|
||||||
margin: 5px 0 5px 5px;
|
|
||||||
|
.adf-left {
|
||||||
|
padding: 0 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-like-select {
|
.adf-like-select {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #2196f3;
|
@include selected;
|
||||||
|
&:hover {
|
||||||
|
@include unselected;
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-like-select:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #808080;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-like-grey {
|
.adf-like-grey {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #808080;
|
@include unselected;
|
||||||
|
&:hover {
|
||||||
|
@include selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-like-grey:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #2196f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-like-counter {
|
|
||||||
float: left;
|
|
||||||
padding: 13px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-left {
|
|
||||||
float: left;
|
|
||||||
padding: 13px 0 0 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,18 @@
|
|||||||
<mat-list id="adf-rating-container" class="adf-rating-container">
|
<mat-list id="adf-rating-container" class="adf-rating-container">
|
||||||
<mat-list-item class="adf-rating-star" *ngFor="let currentRate of stars; let idx = index">
|
<mat-list-item class="adf-rating-star" *ngFor="let currentRate of stars; let idx = index;">
|
||||||
<span id="adf-rate-{{idx}}">
|
<span id="adf-rate-{{idx}}">
|
||||||
<mat-icon id="adf-grey-star-{{idx}}" *ngIf="currentRate.fill" class="adf-colored-star"
|
<mat-icon id="adf-colored-star-{{idx}}" *ngIf="currentRate.fill" class="adf-colored-star"
|
||||||
|
[ngClass]="{'adf-average-star': !ratingValue}"
|
||||||
(click)="updateVote(idx + 1)">star_rate
|
(click)="updateVote(idx + 1)">star_rate
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
<mat-icon id="adf-colored-star-{{idx}}" *ngIf="!currentRate.fill" class="adf-grey-star"
|
<mat-icon id="adf-grey-star-{{idx}}" *ngIf="!currentRate.fill" class="adf-grey-star"
|
||||||
(click)="updateVote(idx + 1)">star_border
|
(click)="updateVote(idx + 1)">star_border
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
</span>
|
</span>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
|
<div class="adf-rating-counter-container">
|
||||||
|
<div id="adf-rating-counter" class="adf-rating-counter">{{ratingsCounter}}</div>
|
||||||
|
<div class="adf-rating-left" *ngIf="ratingsCounter<=1">Rating</div>
|
||||||
|
<div class="adf-rating-left" *ngIf="ratingsCounter>1">Ratings</div>
|
||||||
|
</div>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
|
@@ -1,35 +1,54 @@
|
|||||||
|
$adf-rated-star-color: #ffe944;
|
||||||
|
$adf-average-star-color: #808080;
|
||||||
|
|
||||||
.adf-rating-container {
|
.adf-rating-container {
|
||||||
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
.adf-rating-counter-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adf-rating-left {
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.adf-rating-star {
|
.adf-rating-star {
|
||||||
float: left;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
padding: 1px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 25px !important;
|
width: 25px;
|
||||||
|
|
||||||
.mat-list-item-content {
|
.mat-list-item-content {
|
||||||
padding: 0 2px !important;
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: rotate(13deg) scale(1.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-colored-star {
|
.adf-colored-star {
|
||||||
color: #ffe944;
|
color: $adf-rated-star-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-grey-star {
|
.adf-grey-star, .adf-average-star {
|
||||||
color: #808080;
|
color: $adf-average-star-color !important;
|
||||||
}
|
|
||||||
|
|
||||||
.adf-stars-container {
|
|
||||||
padding: 0 !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.adf-rating-star:hover {
|
|
||||||
transform: rotate(13deg) scale(1.2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[dir='rtl'] .adf-rating-container {
|
||||||
|
|
||||||
|
.adf-rating-star {
|
||||||
|
transform: rotate(145deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.adf-rating-star:hover {
|
||||||
|
transform: rotate(158deg) scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -61,28 +61,26 @@ describe('Rating component', () => {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
component.ngOnChanges().subscribe(() => {
|
|
||||||
expect(element.querySelector('#adf-rating-container')).not.toBe(null);
|
expect(element.querySelector('#adf-rating-container')).not.toBe(null);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should the star rating filled with the right grey/colored star', (done) => {
|
it('should the star rating filled with the right grey/colored star', (done) => {
|
||||||
spyOn(service, 'getRating').and.returnValue(of({
|
spyOn(service, 'getRating').and.returnValue(of({
|
||||||
entry: {
|
'entry': {
|
||||||
id: 'fiveStar',
|
myRating: 3,
|
||||||
aggregate: {
|
'ratedAt': '2017-04-06T14:34:28.061+0000',
|
||||||
numberOfRatings: 4,
|
'id': 'fiveStar',
|
||||||
average: 3
|
'aggregate': {'numberOfRatings': 1, 'average': 3.0}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fixture.detectChanges();
|
component.ngOnChanges();
|
||||||
|
|
||||||
component.ngOnChanges().subscribe(() => {
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
|
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
|
||||||
@@ -91,45 +89,59 @@ describe('Rating component', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should click on a star change your vote', (done) => {
|
it('should click on a star to change your vote', (done) => {
|
||||||
spyOn(service, 'getRating').and.returnValue(of({
|
spyOn(service, 'getRating').and.returnValue(of({
|
||||||
'entry': {
|
'entry': {
|
||||||
myRating: 1,
|
myRating: 1,
|
||||||
'ratedAt': '2017-04-06T14:34:28.061+0000',
|
'ratedAt': '2017-04-06T14:34:28.061+0000',
|
||||||
'id': 'fiveStar',
|
'id': 'fiveStar',
|
||||||
'aggregate': { 'numberOfRatings': 1, 'average': 1.0 }
|
'aggregate': {'numberOfRatings': 1, 'average': 1.0}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
spyOn(service, 'postRating').and.returnValue(of({
|
const rateSpy = spyOn(service, 'postRating').and.returnValue(of({
|
||||||
'entry': {
|
'entry': {
|
||||||
'myRating': 3,
|
'myRating': 3,
|
||||||
'ratedAt': '2017-04-06T14:36:40.731+0000',
|
'ratedAt': '2017-04-06T14:36:40.731+0000',
|
||||||
'id': 'fiveStar',
|
'id': 'fiveStar',
|
||||||
'aggregate': { 'numberOfRatings': 1, 'average': 3.0 }
|
'aggregate': {'numberOfRatings': 1, 'average': 3.0}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fixture.detectChanges();
|
component.ngOnChanges();
|
||||||
|
|
||||||
component.ngOnChanges().subscribe(() => {
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(element.querySelectorAll('.adf-colored-star').length).toBe(1);
|
expect(element.querySelectorAll('.adf-colored-star').length).toBe(1);
|
||||||
|
|
||||||
component.changeVote.subscribe(() => {
|
component.changeVote.subscribe(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
expect(rateSpy).toHaveBeenCalled();
|
||||||
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
|
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
const starThree: any = element.querySelector('#adf-colored-star-3');
|
const starThree: any = element.querySelector('#adf-grey-star-2');
|
||||||
starThree.click();
|
starThree.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
it('should click on the rated star to remove your vote', () => {
|
||||||
|
spyOn(service, 'getRating').and.returnValue(of({
|
||||||
|
'entry': {
|
||||||
|
myRating: 3,
|
||||||
|
'ratedAt': '2017-04-06T14:34:28.061+0000',
|
||||||
|
'id': 'fiveStar',
|
||||||
|
'aggregate': {'numberOfRatings': 1, 'average': 3.0}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const deleteSpy = spyOn(service, 'deleteRating');
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.detectChanges();
|
||||||
|
const starThree: any = element.querySelector('#adf-colored-star-2');
|
||||||
|
starThree.click();
|
||||||
|
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
|
||||||
|
expect(deleteSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -18,6 +18,8 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core';
|
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core';
|
||||||
import { RatingService } from './services/rating.service';
|
import { RatingService } from './services/rating.service';
|
||||||
import { RatingEntry } from '@alfresco/js-api';
|
import { RatingEntry } from '@alfresco/js-api';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-rating',
|
selector: 'adf-rating',
|
||||||
@@ -33,56 +35,87 @@ export class RatingComponent implements OnChanges {
|
|||||||
|
|
||||||
average: number = 0;
|
average: number = 0;
|
||||||
|
|
||||||
|
ratingsCounter = 0;
|
||||||
|
|
||||||
ratingType: string = 'fiveStar';
|
ratingType: string = 'fiveStar';
|
||||||
|
|
||||||
|
ratingValue: number;
|
||||||
|
|
||||||
/** Emitted when the "vote" gets changed. */
|
/** Emitted when the "vote" gets changed. */
|
||||||
@Output()
|
@Output()
|
||||||
changeVote = new EventEmitter();
|
changeVote = new EventEmitter();
|
||||||
|
|
||||||
stars: Array<any> = [];
|
stars: Array<any> = [];
|
||||||
|
|
||||||
|
onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(private ratingService: RatingService) {
|
constructor(private ratingService: RatingService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
const ratingObserver = this.ratingService.getRating(this.nodeId, this.ratingType);
|
this.ratingService.getRating(this.nodeId, this.ratingType)
|
||||||
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
ratingObserver.subscribe(
|
.subscribe(
|
||||||
(ratingEntry: RatingEntry) => {
|
(ratingEntry: RatingEntry) => {
|
||||||
if (ratingEntry.entry.aggregate) {
|
this.refreshRating(ratingEntry);
|
||||||
this.average = ratingEntry.entry.aggregate.average;
|
|
||||||
this.calculateStars();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return ratingObserver;
|
ngOnDestroy() {
|
||||||
|
this.onDestroy$.next(true);
|
||||||
|
this.onDestroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateStars() {
|
calculateStars() {
|
||||||
this.stars = [];
|
this.stars = [];
|
||||||
|
const roundedAverage = Math.round(this.average);
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
if (i < this.average) {
|
if (i < roundedAverage) {
|
||||||
this.stars.push({ fill: true });
|
this.stars.push({fill: true});
|
||||||
} else {
|
} else {
|
||||||
this.stars.push({ fill: false });
|
this.stars.push({fill: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changeVote.emit(this.average);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVote(vote: number) {
|
updateVote(vote: number) {
|
||||||
this.ratingService.postRating(this.nodeId, this.ratingType, vote).subscribe(
|
if (this.ratingValue === vote) {
|
||||||
|
this.unRateItem();
|
||||||
|
} else {
|
||||||
|
this.rateItem(vote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rateItem(vote: number) {
|
||||||
|
this.ratingService.postRating(this.nodeId, this.ratingType, vote)
|
||||||
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
|
.subscribe(
|
||||||
(ratingEntry: RatingEntry) => {
|
(ratingEntry: RatingEntry) => {
|
||||||
if (ratingEntry.entry.aggregate) {
|
this.refreshRating(ratingEntry);
|
||||||
if (this.average !== ratingEntry.entry.aggregate.average) {
|
|
||||||
this.average = ratingEntry.entry.aggregate.average;
|
|
||||||
this.calculateStars();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unRateItem() {
|
||||||
|
this.ratingService.deleteRating(this.nodeId, this.ratingType).subscribe(
|
||||||
|
() => {
|
||||||
|
this.ratingService.getRating(this.nodeId, this.ratingType)
|
||||||
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
|
.subscribe(
|
||||||
|
(ratingEntry: RatingEntry) => {
|
||||||
|
this.refreshRating(ratingEntry);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshRating(ratingEntry: RatingEntry) {
|
||||||
|
this.ratingValue = Number.parseFloat(ratingEntry.entry.myRating);
|
||||||
|
this.average = ratingEntry.entry.aggregate.average;
|
||||||
|
this.ratingsCounter = ratingEntry.entry.aggregate.numberOfRatings;
|
||||||
|
this.calculateStars();
|
||||||
|
this.changeVote.emit(this.average);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
50
lib/testing/src/lib/content-services/pages/like.page.ts
Normal file
50
lib/testing/src/lib/content-services/pages/like.page.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
import { BrowserActions } from '../../core/utils/browser-actions';
|
||||||
|
|
||||||
|
export class LikePage {
|
||||||
|
|
||||||
|
likeCounter = element(by.css(`div[id="adf-like-counter"]`));
|
||||||
|
likeButton = element(by.css(`span[class="adf-like-grey"]`));
|
||||||
|
unlikeButton = element(by.css(`span[class="adf-like-select"]`));
|
||||||
|
|
||||||
|
getLikeCounter() {
|
||||||
|
return BrowserActions.getText(this.likeCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
clickLike() {
|
||||||
|
return BrowserActions.click(this.likeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
clickUnlike() {
|
||||||
|
return BrowserActions.click(this.unlikeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeHoverFromLikeButton() {
|
||||||
|
browser.actions().mouseMove({x: 200, y: 200}).click().perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
getLikedIconColor() {
|
||||||
|
return BrowserActions.getColor(this.unlikeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnLikedIconColor() {
|
||||||
|
return BrowserActions.getColor(this.likeButton);
|
||||||
|
}
|
||||||
|
}
|
@@ -15,4 +15,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export * from './like.page';
|
||||||
|
export * from './rate.page';
|
||||||
export * from './document-list.page';
|
export * from './document-list.page';
|
||||||
|
64
lib/testing/src/lib/content-services/pages/rate.page.ts
Normal file
64
lib/testing/src/lib/content-services/pages/rate.page.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { by, element } from 'protractor';
|
||||||
|
import { BrowserVisibility } from '../../core/utils/browser-visibility';
|
||||||
|
import { BrowserActions } from '../../core/utils/browser-actions';
|
||||||
|
|
||||||
|
export class RatePage {
|
||||||
|
|
||||||
|
rateComponent(rateValue: number) {
|
||||||
|
const unratedStar = element(by.css(`span[id="adf-rate-${rateValue}"]`));
|
||||||
|
return BrowserActions.click(unratedStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRating(rateValue: number) {
|
||||||
|
const ratedStar = element(by.css(`mat-icon[id="adf-colored-star-${rateValue}"]`));
|
||||||
|
return BrowserActions.click(ratedStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRatingCounter() {
|
||||||
|
const ratingsCounter = element(by.css(`div[id="adf-rating-counter"]`));
|
||||||
|
return BrowserActions.getText(ratingsCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
isStarRated(rateValue: number) {
|
||||||
|
const ratedStar = element(by.css(`mat-icon[id="adf-colored-star-${rateValue}"]`));
|
||||||
|
return BrowserVisibility.waitUntilElementIsVisible(ratedStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
isNotStarRated(rateValue: number) {
|
||||||
|
const unratedStar = element(by.css(`mat-icon[id="adf-grey-star-${rateValue}"]`));
|
||||||
|
return BrowserVisibility.waitUntilElementIsVisible(unratedStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRatedStarColor(rateValue: number) {
|
||||||
|
const ratedStar = element(by.css(`mat-icon[id="adf-colored-star-${rateValue}"]`));
|
||||||
|
return BrowserActions.getColor(ratedStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUnratedStarColor(rateValue: number) {
|
||||||
|
const unratedStar = element(by.css(`mat-icon[id="adf-grey-star-${rateValue}"]`));
|
||||||
|
return BrowserActions.getColor(unratedStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAverageStarColor(rateValue: number) {
|
||||||
|
const coloredStar = element(by.css(`mat-icon[id="adf-colored-star-${rateValue}"]`));
|
||||||
|
return BrowserActions.getColor(coloredStar);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -40,6 +40,11 @@ export class BrowserActions {
|
|||||||
return elementFinder.getText();
|
return elementFinder.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getColor(elementFinder: ElementFinder) {
|
||||||
|
BrowserVisibility.waitUntilElementIsVisible(elementFinder);
|
||||||
|
return elementFinder.getWebElement().getCssValue('color');
|
||||||
|
}
|
||||||
|
|
||||||
static async clearSendKeys(elementFinder: ElementFinder, text: string) {
|
static async clearSendKeys(elementFinder: ElementFinder, text: string) {
|
||||||
BrowserVisibility.waitUntilElementIsVisible(elementFinder);
|
BrowserVisibility.waitUntilElementIsVisible(elementFinder);
|
||||||
elementFinder.click();
|
elementFinder.click();
|
||||||
|
@@ -235,7 +235,7 @@
|
|||||||
"typings": "./index.d.ts",
|
"typings": "./index.d.ts",
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"linters": {
|
"linters": {
|
||||||
"**/demo-shell/**/*.ts": "npm run lint-lib -- --fix",
|
"**/demo-shell/src/**/*.ts": "npm run lint-lib -- --fix",
|
||||||
"**/lib/**/*.ts": "npm run lint-lib -- --fix",
|
"**/lib/**/*.ts": "npm run lint-lib -- --fix",
|
||||||
"**/e2e/**/*.ts": "npm run lint-e2e -- --fix",
|
"**/e2e/**/*.ts": "npm run lint-e2e -- --fix",
|
||||||
"*.scss": "npm run stylelint -- --fix"
|
"*.scss": "npm run stylelint -- --fix"
|
||||||
|
Reference in New Issue
Block a user