Skip to content

Commit

Permalink
New TestControl API, rename testControl.ts to testSetup
Browse files Browse the repository at this point in the history
New API entries in testSetup.ts:

* initTestProject to create new, empty project
* addCustomField to add a custom field to a project
* addLexEntry to add a lexical entry to a project
* getProjectJson for help with logging or expect()ing project config
* changePassword API moved from testControl.ts to testSetup.ts

Also added some examples in example.spec.ts showing how to use the
testSetup API. Each example is in a `test.skip` block so that they will
not actually run by default.
  • Loading branch information
rmunn committed Mar 30, 2022
1 parent 00d1bab commit 8b41f53
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 29 deletions.
2 changes: 1 addition & 1 deletion test/e2e/change-password.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import { test } from './utils/fixtures';
import { ChangePasswordPage } from './pages/change-password.page';
import { changePassword } from './utils/testControl';
import { changePassword } from './utils/testSetup';
import { LoginPage } from './pages/login.page';
import { PageHeader } from './pages/page-header.page';

Expand Down
46 changes: 30 additions & 16 deletions test/e2e/example.spec.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
import type { APIRequestContext } from '@playwright/test';
import { expect } from '@playwright/test';
import constants from './testConstants.json';
import { testControl } from './utils/jsonrpc';
import type { UserTab } from './utils/fixtures';
import { test } from './utils/fixtures';
import { addCustomField, addLexEntry, initTestProject } from './utils/testSetup';

test('API call', async ({ request }: { request: APIRequestContext }) => {
const result = await testControl(request, 'check_test_api');
expect(result).toBeDefined();
expect(result).toHaveProperty('api_is_working');
expect(result.api_is_working).toBeTruthy();
test.skip('Reset project', async ({ request }) => {
await initTestProject(request,
constants.testProjectCode,
constants.testProjectName,
constants.adminUsername,
);
});

test('Reset project', async ({ request, adminTab }: { request: APIRequestContext, adminTab: UserTab }) => {
const result = await testControl(request, 'init_test_project', [
test.skip('Reset project and add test data', async ({ request }) => {
await initTestProject(request,
constants.testProjectCode,
constants.testProjectName,
constants.adminUsername,
]);
await adminTab.goto('/app/projects');
await expect(adminTab.locator(`[data-ng-repeat="project in visibleProjects"] a:has-text("${constants.testProjectName}")`)).toBeVisible();
// await adminTab.screenshot({ path: 'post-login.png' });
constants.managerUsername,
);
const customFieldName = await addCustomField(request,
constants.testProjectCode,
'CustomField',
'entry',
'MultiString',
{inputSystems: ['th']}
);
// Lexical entry from testConstants.json with no changes
await addLexEntry(request, constants.testProjectCode, constants.testEntry1);
// Example of adding data in the custom field
const data = {
...constants.testEntry2,
customFields: {
[customFieldName]: { th: { value: 'contents of custom field' } }
}
};
// The [customFieldName] syntax is how you can assign a property without knowing it at compile-time
// console.log(data); // Uncomment this to see the data you're adding
await addLexEntry(request, constants.testProjectCode, data);
});
1 change: 1 addition & 0 deletions test/e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"extends": "../../tsconfig.json",
"buildOnSave": false,
"compileOnSave": false,
"compilerOptions": {
Expand Down
129 changes: 123 additions & 6 deletions test/e2e/utils/TestControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@

namespace Api\Service;
use Api\Model\Shared\Mapper\MongoStore;
use Api\Model\Shared\Mapper\ArrayOf;
use Api\Model\Shared\Command\UserCommands;
use Api\Model\Shared\ProjectModel;
use Api\Model\Shared\UserModel;
use Api\Model\Shared\UserModelWithPassword;
use Api\Model\Languageforge\Lexicon\LexEntryModel;
use Api\Model\Languageforge\Lexicon\LexProjectModel;
use Api\Model\Languageforge\Lexicon\Config\LexConfig;
use Api\Model\Languageforge\Lexicon\Config\LexConfigOptionList;
use Api\Model\Languageforge\Lexicon\Config\LexConfigMultiOptionList;
use Api\Model\Languageforge\Lexicon\Config\LexConfigMultiParagraph;
use Api\Model\Languageforge\Lexicon\Config\LexConfigMultiText;
use Api\Model\Languageforge\Lexicon\Config\LexRoleViewConfig;
use Api\Model\Languageforge\Lexicon\Config\LexUserViewConfig;
use Api\Model\Languageforge\Lexicon\Config\LexViewFieldConfig;
use Api\Model\Languageforge\Lexicon\Config\LexViewMultiTextFieldConfig;
use Api\Model\Shared\Rights\ProjectRoles;
use Api\Model\Shared\Rights\SystemRoles;
use Api\Model\Shared\Mapper\IdReference;

use Api\Model\Languageforge\Lexicon\Command\LexEntryDecoder;
use Api\Model\Languageforge\Lexicon\Command\LexProjectCommands;
// use MongoDB\Client;

use Api\Library\Shared\Website;
Expand Down Expand Up @@ -99,7 +111,15 @@ public function change_password($username, $password)
return '';
}

public function init_test_project($projectCode = null, $projectName = null, $ownerUsername = null)
public function reset_projects()
{
$db = MongoStore::connect(DATABASE);
$db->dropCollection('projects');
$db->createCollection('projects');
return true;
}

public function init_test_project($projectCode = null, $projectName = null, $ownerUsername = null, $memberUsernames = [])
{
if (! $projectCode) {
$projectCode = 'test_project';
Expand All @@ -108,7 +128,6 @@ public function init_test_project($projectCode = null, $projectName = null, $own
$projectName = 'Test Project';
}

// TODO: Handle this with MongoStore instead of through Commands library
$owner = new UserModel();
$ownerId = '';
if ($owner->readByUserName($ownerUsername)) {
Expand All @@ -117,21 +136,119 @@ public function init_test_project($projectCode = null, $projectName = null, $own
$ownerId = $this->create_user($ownerUsername);
}


$db = MongoStore::connect(DATABASE);
$db->dropCollection('projects');
$db->createCollection('projects');
$coll = $db->selectCollection('projects');
$coll->deleteOne([ 'projectCode' => $projectCode ]);
$projectModel = new ProjectModel();
$projectModel->projectName = $projectName;
$projectModel->projectCode = $projectCode;
$projectModel->appName = LexProjectModel::LEXICON_APP;
$projectModel->siteName = $this->website->domain;
$projectModel->ownerRef = new IdReference($ownerId);
$projectModel->addUser($ownerId, ProjectRoles::MANAGER);
foreach ($memberUsernames as $username) {
$user = new UserModel();
if ($user->readByUserName($username)) {
$userId = $user->id->asString();
$projectModel->addUser($userId, ProjectRoles::CONTRIBUTOR);
}
}
MongoStore::dropAllCollections($projectModel->databaseName());
MongoStore::dropDB($projectModel->databaseName());
$projectModel->write();
return $projectModel->id->asString();
}

public function add_custom_field(string $projectCode, string $customFieldName, string $parentField = 'entry', string $customFieldType = 'MultiString', $extraOptions = null)
{
error_log('add_custom_field');
$prefix = 'customField_' . $parentField . '_';
if (\strpos($customFieldName, $prefix) !== 0) {
$customFieldName = $prefix . $customFieldName;
}
$project = ProjectModel::getByProjectCode($projectCode);
error_log($project->id->asString());
switch($parentField) {
case 'entry': $config = $project->config->entry; break;
case 'senses': $config = $project->config->entry->fields[LexConfig::SENSES_LIST]; break;
case 'examples': $config = $project->config->entry->fields[LexConfig::SENSES_LIST]->fields[LexConfig::EXAMPLES_LIST]; break;
}
$config->fieldOrder->ensureValueExists($customFieldName);
if (! array_key_exists($customFieldName, $config->fields)) {
switch($customFieldType) {
case "ReferenceAtom":
$config->fields[$customFieldName] = new LexConfigOptionList();
$config->fields[$customFieldName]->listCode = $extraOptions['listCode'];
break;
case "ReferenceCollection":
$config->fields[$customFieldName] = new LexConfigMultiOptionList();
$config->fields[$customFieldName]->listCode = $extraOptions['listCode'];
break;
case "OwningAtom":
$config->fields[$customFieldName] = new LexConfigMultiParagraph();
break;
default:
$config->fields[$customFieldName] = new LexConfigMultiText();
$config->fields[$customFieldName]->inputSystems = new ArrayOf();
if ($extraOptions['inputSystems']) {
foreach ($extraOptions['inputSystems'] as $ws) {
$config->fields[$customFieldName]->inputSystems->ensureValueExists($ws);
}
}
};
$label = str_replace($prefix, '', $customFieldName);
$config->fields[$customFieldName]->label = str_replace(' ', '_', $label);
$config->fields[$customFieldName]->hideIfEmpty = false;
}
// PHP copies objects by value, not reference, so now we have to write the config back
switch($parentField) {
case 'entry': $project->config->entry = $config; break;
case 'senses': $project->config->entry->fields[LexConfig::SENSES_LIST] = $config; break;
case 'examples': $project->config->entry->fields[LexConfig::SENSES_LIST]->fields[LexConfig::EXAMPLES_LIST] = $config; break;
}

// Now make the custom field visible in all views
foreach ($project->config->roleViews as $role => $roleView) {
if (!array_key_exists($customFieldName, $roleView->fields)) {
if ($customFieldType == 'MultiUnicode' || $customFieldType == 'MultiString') {
$roleView->fields[$customFieldName] = new LexViewMultiTextFieldConfig();
} else {
$roleView->fields[$customFieldName] = new LexViewFieldConfig();
}
$roleView->fields[$customFieldName]->show = true;
}
}
foreach ($project->config->userViews as $userId => $userView) {
if (!array_key_exists($customFieldName, $userView->fields)) {
if ($customFieldType == 'MultiUnicode' || $customFieldType == 'MultiString') {
$userView->fields[$customFieldName] = new LexViewMultiTextFieldConfig();
} else {
$userView->fields[$customFieldName] = new LexViewFieldConfig();
}
$userView->fields[$customFieldName]->show = true;
}
}

$project->write();

return $customFieldName;
}

public function add_lexical_entry(string $projectCode, array $data)
{
$project = ProjectModel::getByProjectCode($projectCode);
$entry = new LexEntryModel($project);
LexEntryDecoder::decode($entry, $data);
return $entry->write();
}

public function get_project_json(string $projectCode) {
$db = MongoStore::connect(DATABASE);
$project = $db->projects->findOne(['projectCode' => $projectCode]);
return $project;
}

public function new_method() {
return 'hello';
}
}
6 changes: 0 additions & 6 deletions test/e2e/utils/testControl.ts

This file was deleted.

51 changes: 51 additions & 0 deletions test/e2e/utils/testSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { testControl } from './jsonrpc';
import { APIRequestContext } from '@playwright/test';

type CustomFieldType =
'MultiString' |
'ReferenceAtom' |
'ReferenceCollection' |
'OwningAtom'
// TODO: Add more (look at LfMerge custom field code to find out what they can be)
;

type LfFieldType =
'fields' |
'multitext' |
'multiparagraph' |
'optionlist' |
'multioptionlist' |
'pictures'
;

export function initTestProject(request: APIRequestContext,
projectCode: string,
projectName: string,
ownerUsername: string,
memberUsernames: string[] = [])
{
return testControl(request, 'init_test_project', [projectCode, projectName, ownerUsername, memberUsernames]);
}

export function addCustomField(request: APIRequestContext,
projectCode: string,
fieldName: string,
parentField: 'entry' | 'senses' | 'examples',
fieldType: CustomFieldType = 'MultiString',
extraOptions: any = null) {
return testControl(request, 'add_custom_field', [projectCode, fieldName, parentField, fieldType, extraOptions]);
}

export function getProjectJson(request: APIRequestContext,
projectCode: string) {
return testControl(request, 'get_project_json', [projectCode]);
}

export function changePassword(request: APIRequestContext, username: string, password: string) {
return testControl(request, 'change_password', [username, password]);
}

export function addLexEntry(request: APIRequestContext, projectCode: string, data: any) {
if (data.id == null) data.id = '';
return testControl(request, 'add_lexical_entry', [projectCode, data]);
}

0 comments on commit 8b41f53

Please sign in to comment.