Skip to content

Commit

Permalink
[ADF-4552][ADF-4482] Social component refactoring, add ability to unR…
Browse files Browse the repository at this point in the history
…ate, added e2e automation (Alfresco#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
  • Loading branch information
arditdomi authored and eromano committed Jun 3, 2019
1 parent b19646d commit 3d67d9d
Show file tree
Hide file tree
Showing 17 changed files with 567 additions and 120 deletions.
12 changes: 10 additions & 2 deletions docs/content-services/components/rating.component.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ Last reviewed: 2019-01-14

# [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.

![Rating component screenshot](../../docassets/images/social3.png)

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

![Rating component screenshot](../../docassets/images/social2.png)

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

```html
Expand All @@ -31,7 +39,7 @@ Allows a user to add ratings to an item.

| 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

Expand Down
Binary file modified docs/docassets/images/social2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/docassets/images/social3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
209 changes: 209 additions & 0 deletions e2e/content-services/social/social.component.e2e.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 34 additions & 0 deletions e2e/pages/adf/demo-shell/socialPage.ts
Original file line number Diff line number Diff line change
@@ -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);
}

}
4 changes: 4 additions & 0 deletions e2e/pages/adf/navigationBarPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export class NavigationBarPage {
BrowserActions.clickExecuteScript(`.adf-sidenav-link[data-automation-id="${title}"]`);
}

async clickSocialButton() {
this.clickMenuButton('Social');
}

async clickTagButton() {
this.clickMenuButton('Tag');
}
Expand Down
8 changes: 5 additions & 3 deletions lib/content-services/social/like.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
<mat-icon>thumb_up</mat-icon>
</span>
</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">Likes</div>
<div class="adf-like-counter-container">
<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">Likes</div>
</div>
</div>
51 changes: 25 additions & 26 deletions lib/content-services/social/like.component.scss
Original file line number Diff line number Diff line change
@@ -1,42 +1,41 @@
@mixin selected {
color: #2196f3;
}

@mixin unselected {
color: #808080;
}

.adf-like-container {
display: flex;
overflow: hidden;
width: 100%;
align-items: center;
margin-top: 13px;

.adf-like {
padding: 5px;
cursor: pointer;
float: left;
margin: 5px 0 5px 5px;
.adf-like-counter-container {
display: inherit;
padding: 0 6px;
}

.adf-like-select {
cursor: pointer;
color: #2196f3;
.adf-left {
padding: 0 6px;
}

.adf-like-select:hover {
.adf-like-select {
cursor: pointer;
color: #808080;
@include selected;
&:hover {
@include unselected;
}
}

.adf-like-grey {
cursor: pointer;
color: #808080;
}

.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;
@include unselected;
&:hover {
@include selected;
}
}

}
16 changes: 11 additions & 5 deletions lib/content-services/social/rating.component.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<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}}">
<mat-icon id="adf-grey-star-{{idx}}" *ngIf="currentRate.fill" class="adf-colored-star"
(click)="updateVote(idx + 1)">star_rate
<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
</mat-icon>
<mat-icon id="adf-colored-star-{{idx}}" *ngIf="!currentRate.fill" class="adf-grey-star"
(click)="updateVote(idx + 1)">star_border
<mat-icon id="adf-grey-star-{{idx}}" *ngIf="!currentRate.fill" class="adf-grey-star"
(click)="updateVote(idx + 1)">star_border
</mat-icon>
</span>
</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>
Loading

0 comments on commit 3d67d9d

Please sign in to comment.