UBERF-8584: Add test runs (#7235)

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artyom Savchenko
2024-11-29 01:36:41 +07:00
committed by GitHub
parent 61f7770a02
commit da85d6dd5f
60 changed files with 2379 additions and 554 deletions
@@ -1,51 +0,0 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 { type Builder } from '@hcengineering/model'
import core from '@hcengineering/model-core'
import { TDefaultProjectTypeData } from './types'
import testManagement from './plugin'
export function defineDefaultSpace (builder: Builder): void {
defineDefaultProject(builder)
}
function defineDefaultProject (builder: Builder): void {
builder.createModel(TDefaultProjectTypeData)
builder.createDoc(
core.class.SpaceTypeDescriptor,
core.space.Model,
{
name: testManagement.string.TestProject,
description: testManagement.string.FullDescription,
icon: testManagement.icon.TestProject,
baseClass: testManagement.class.TestProject,
availablePermissions: [
core.permission.UpdateSpace,
core.permission.ArchiveSpace,
core.permission.ForbidDeleteObject
]
},
testManagement.descriptors.ProjectType
)
builder.createDoc(core.class.SpaceType, core.space.Model, {
name: 'Default project type',
descriptor: testManagement.descriptors.ProjectType,
roles: 0,
targetClass: testManagement.mixin.DefaultProjectTypeData
})
}
+151 -46
View File
@@ -16,7 +16,7 @@
import activity from '@hcengineering/activity'
import chunter from '@hcengineering/chunter'
import core from '@hcengineering/model-core'
import { SortingOrder } from '@hcengineering/core'
import { SortingOrder, type FindOptions } from '@hcengineering/core'
import { type Builder } from '@hcengineering/model'
import view, { createAction } from '@hcengineering/model-view'
@@ -25,7 +25,7 @@ import print from '@hcengineering/model-print'
import tracker from '@hcengineering/model-tracker'
import { type ViewOptionsModel } from '@hcengineering/view'
import { testManagementId } from '@hcengineering/test-management'
import { testManagementId, type TestResult } from '@hcengineering/test-management'
import {
DOMAIN_TEST_MANAGEMENT,
@@ -37,8 +37,8 @@ import {
TTestCase,
TDefaultProjectTypeData,
TTestRun,
TTypeTestRunResult,
TTestRunItem
TTypeTestRunStatus,
TTestResult
} from './types'
import testManagement from './plugin'
@@ -55,7 +55,6 @@ function defineApplication (builder: Builder): void {
icon: testManagement.icon.TestManagementApplication,
alias: testManagementId,
hidden: false,
locationResolver: testManagement.resolver.Location,
navigatorModel: {
spaces: [
{
@@ -85,6 +84,7 @@ function defineApplication (builder: Builder): void {
mainComponentLabel: testManagement.string.TestCases,
mainComponentIcon: testManagement.icon.TestCases,
createComponent: testManagement.component.CreateTestSuite,
mainHeaderComponent: testManagement.component.RunSelectedTestsButton,
navigationComponentProps: {
_class: testManagement.class.TestSuite,
icon: testManagement.icon.TestSuites,
@@ -100,21 +100,34 @@ function defineApplication (builder: Builder): void {
},
syncWithLocationQuery: true
}
}
/* TODO: UBERF-8584
},
{
id: opt.testRunsId,
id: 'testRuns',
label: testManagement.string.TestRuns,
icon: testManagement.icon.TestRuns,
component: workbench.component.SpecialView,
componentProps: {
_class: testManagement.class.TestRun,
_class: testManagement.class.TestResult,
icon: testManagement.icon.TestRuns,
title: testManagement.string.TestRuns,
createLabel: testManagement.string.NewTestRun,
createComponent: testManagement.component.CreateTestRun
label: testManagement.string.TestRuns
},
navigationModel: {
navigationComponent: view.component.FoldersBrowser,
navigationComponentLabel: testManagement.string.TestRun,
navigationComponentIcon: testManagement.icon.TestRuns,
mainComponentLabel: testManagement.string.TestResults,
mainComponentIcon: testManagement.icon.TestResult,
navigationComponentProps: {
_class: testManagement.class.TestRun,
icon: testManagement.icon.TestRuns,
title: testManagement.string.TestSuites,
titleKey: 'name',
getFolderLink: testManagement.function.GetTestRunLink,
plainList: true
},
syncWithLocationQuery: true
}
} */
}
]
}
]
@@ -135,8 +148,8 @@ export function createModel (builder: Builder): void {
TTestCase,
TDefaultProjectTypeData,
TTestRun,
TTestRunItem,
TTypeTestRunResult
TTypeTestRunStatus,
TTestResult
)
builder.mixin(testManagement.class.TestProject, core.class.Class, activity.mixin.ActivityDoc, {})
@@ -204,7 +217,7 @@ function defineSpaceType (builder: Builder): void {
core.class.SpaceType,
core.space.Model,
{
name: 'Default project type',
name: 'Default Test Management',
descriptor: testManagement.descriptors.ProjectType,
roles: 0,
targetClass: testManagement.mixin.DefaultProjectTypeData
@@ -250,13 +263,7 @@ function defineTestSuite (builder: Builder): void {
// Actions
builder.mixin(testManagement.class.TestSuite, core.class.Class, view.mixin.IgnoreActions, {
actions: [
view.action.Open,
view.action.OpenInNewTab,
print.action.Print,
tracker.action.EditRelatedTargets,
tracker.action.NewRelatedIssue
]
actions: [print.action.Print, tracker.action.EditRelatedTargets]
})
createAction(
@@ -276,6 +283,24 @@ function defineTestSuite (builder: Builder): void {
},
testManagement.action.CreateChildTestSuite
)
createAction(
builder,
{
action: testManagement.actionImpl.RunSelectedTests,
label: testManagement.string.CreateTestRun,
icon: testManagement.icon.TestRuns,
category: testManagement.category.TestCase,
input: 'selection',
target: testManagement.class.TestCase,
context: {
mode: ['context'],
application: testManagement.app.TestManagement,
group: 'create'
}
},
testManagement.action.RunSelectedTests
)
}
function defineTestCase (builder: Builder): void {
@@ -306,6 +331,11 @@ function defineTestCase (builder: Builder): void {
presenter: testManagement.component.TestSuiteRefPresenter
})
builder.mixin(testManagement.class.TestCase, core.class.Class, view.mixin.ClassFilters, {
filters: ['priority', 'status'],
ignoreKeys: ['createdBy', 'modifiedBy', 'createdOn', 'modifiedOn']
})
builder.createDoc(
view.class.Viewlet,
core.space.Model,
@@ -350,6 +380,7 @@ function defineTestCase (builder: Builder): void {
hiddenKeys: ['title']
},
config: [
{ key: '', displayProps: { fixed: 'left' } },
{
key: 'status',
props: { kind: 'list', size: 'small', shouldShowName: false },
@@ -368,21 +399,6 @@ function defineTestCase (builder: Builder): void {
},
testManagement.viewlet.ListTestCase
)
builder.createDoc(
view.class.Viewlet,
core.space.Model,
{
attachTo: testManagement.class.TestCase,
descriptor: view.viewlet.Table,
config: ['', 'assignee', 'modifiedOn'],
configOptions: {
sortable: true
},
variant: 'short'
},
testManagement.viewlet.SuiteTestCases
)
}
function defineTestRun (builder: Builder): void {
@@ -393,10 +409,6 @@ function defineTestRun (builder: Builder): void {
components: { input: { component: chunter.component.ChatMessageInput } }
})
builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectEditor, {
editor: testManagement.component.EditTestRun
})
builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectPanel, {
component: testManagement.component.EditTestRun
})
@@ -405,18 +417,111 @@ function defineTestRun (builder: Builder): void {
presenter: testManagement.component.TestRunPresenter
})
builder.mixin(testManagement.class.TestRun, core.class.Class, view.mixin.ObjectIcon, {
component: testManagement.component.TestResultStatusPresenter
})
builder.mixin(testManagement.class.TestResult, core.class.Class, view.mixin.ObjectPresenter, {
presenter: testManagement.component.TestResultPresenter
})
builder.mixin(testManagement.class.TestResult, core.class.Class, activity.mixin.ActivityDoc, {})
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
ofClass: testManagement.class.TestResult,
components: { input: { component: chunter.component.ChatMessageInput } }
})
builder.mixin(testManagement.class.TestResult, core.class.Class, view.mixin.ObjectEditor, {
editor: testManagement.component.EditTestResult
})
builder.mixin(testManagement.class.TestResult, core.class.Class, view.mixin.ObjectEditorHeader, {
editor: testManagement.component.TestResultHeader
})
builder.mixin(testManagement.class.TestResult, core.class.Class, view.mixin.ObjectPanel, {
component: testManagement.component.EditTestResult
})
builder.mixin(testManagement.class.TestResult, core.class.Class, view.mixin.ObjectPanelFooter, {
editor: testManagement.component.TestResultFooter
})
builder.mixin(testManagement.class.TestResult, core.class.Class, view.mixin.ClassFilters, {
filters: ['assignee', 'status', 'testSuite'],
ignoreKeys: ['createdBy', 'modifiedBy', 'createdOn', 'modifiedOn']
})
const viewOptions: ViewOptionsModel = {
groupBy: ['testSuite'],
orderBy: [
['status', SortingOrder.Ascending],
['modifiedOn', SortingOrder.Descending],
['createdOn', SortingOrder.Descending]
],
other: [
{
key: 'shouldShowAll',
type: 'toggle',
defaultValue: false,
actionTarget: 'category',
action: view.function.ShowEmptyGroups,
label: view.string.ShowEmptyGroups
}
]
}
builder.createDoc(
view.class.Viewlet,
core.space.Model,
{
attachTo: testManagement.class.TestRun,
attachTo: testManagement.class.TestResult,
descriptor: view.viewlet.List,
configOptions: {
strict: true,
hiddenKeys: ['title', 'status', 'modifiedOn']
},
config: [
{ key: '', displayProps: { fixed: 'left' } },
{
key: 'status',
props: { kind: 'list', size: 'small', shouldShowName: false }
},
{
key: 'assignee',
props: { kind: 'list', shouldShowName: false, avatarSize: 'x-small' },
displayProps: { key: 'assignee', fixed: 'right' }
}
],
viewOptions,
/* eslint-disable @typescript-eslint/consistent-type-assertions */
options: {
lookup: {
testCase: testManagement.class.TestCase
}
} as FindOptions<TestResult>
},
testManagement.viewlet.TestResultList
)
builder.createDoc(
view.class.Viewlet,
core.space.Model,
{
attachTo: testManagement.class.TestResult,
descriptor: view.viewlet.Table,
config: [''],
config: ['', 'testSuite', 'status', 'assignee'],
configOptions: {
strict: true
}
},
options: {
lookup: {
testCase: testManagement.class.TestCase
}
} as FindOptions<TestResult>
},
testManagement.viewlet.TableTestRun
testManagement.viewlet.TableTestResult
)
}
+9 -13
View File
@@ -15,23 +15,15 @@
import { testManagementId } from '@hcengineering/test-management'
import testManganement from '@hcengineering/test-management-resources/src/plugin'
import type { Doc, Ref } from '@hcengineering/core'
import type { Ref } from '@hcengineering/core'
import { mergeIds } from '@hcengineering/platform'
import { type AnyComponent } from '@hcengineering/ui/src/types'
import type { Action, ActionCategory, ViewAction } from '@hcengineering/view'
import type { ActionCategory } from '@hcengineering/view'
export default mergeIds(testManagementId, testManganement, {
action: {
DeleteTestCase: '' as Ref<Action<Doc, any>>,
CreateChildTestSuite: '' as Ref<Action>,
EditTestSuite: '' as Ref<Action>
},
actionImpl: {
CreateChildTestSuite: '' as ViewAction,
EditTestSuite: '' as ViewAction
},
category: {
TestSuite: '' as Ref<ActionCategory>
TestSuite: '' as Ref<ActionCategory>,
TestCase: '' as Ref<ActionCategory>
},
component: {
CreateTestCase: '' as AnyComponent,
@@ -44,6 +36,10 @@ export default mergeIds(testManagementId, testManganement, {
CreateTestRun: '' as AnyComponent,
TestRunPresenter: '' as AnyComponent,
EditTestRun: '' as AnyComponent,
TestSuiteRefPresenter: '' as AnyComponent
TestSuiteRefPresenter: '' as AnyComponent,
RunSelectedTestsButton: '' as AnyComponent,
TestResultPresenter: '' as AnyComponent,
EditTestResult: '' as AnyComponent,
TestResultFooter: '' as AnyComponent
}
})
+8
View File
@@ -53,4 +53,12 @@ export function definePresenters (builder: Builder): void {
builder.mixin(testManagement.class.TypeTestCaseStatus, core.class.Class, view.mixin.AttributePresenter, {
presenter: testManagement.component.TestCaseStatusPresenter
})
builder.mixin(testManagement.class.TypeTestRunStatus, core.class.Class, view.mixin.AttributePresenter, {
presenter: testManagement.component.TestResultStatusPresenter
})
builder.mixin(testManagement.class.TypeTestRunStatus, core.class.Class, view.mixin.AttributeEditor, {
inlineEditor: testManagement.component.TestResultStatusEditor
})
}
+50 -17
View File
@@ -22,8 +22,8 @@ import type {
TestCaseStatus,
TestProject,
TestRun,
TestRunResult,
TestRunItem
TestRunStatus,
TestResult
} from '@hcengineering/test-management'
import { type Attachment } from '@hcengineering/attachment'
import contact from '@hcengineering/contact'
@@ -201,32 +201,65 @@ export class TTestRun extends TDoc implements TestRun {
@Prop(TypeDate(DateRangeMode.DATETIME), testManagement.string.DueDate)
dueDate?: Timestamp
@Prop(Collection(testManagement.class.TestRunItem), testManagement.string.TestRunItems, {
shortLabel: testManagement.string.TestRunItem
@Prop(Collection(testManagement.class.TestResult), testManagement.string.TestResult, {
shortLabel: testManagement.string.TestResult
})
items?: CollectionSize<TestRunItem>
results?: CollectionSize<TestResult>
}
/** @public */
export function TypeTestRunResult (): Type<TestRunResult> {
return { _class: testManagement.class.TypeTestRunResult, label: testManagement.string.TestRunResult }
export function TypeTestRunStatus (): Type<TestRunStatus> {
return { _class: testManagement.class.TypeTestRunStatus, label: testManagement.string.TestRunStatus }
}
@Model(testManagement.class.TypeTestRunResult, core.class.Type, DOMAIN_TEST_MANAGEMENT)
@UX(testManagement.string.TestRunResult)
export class TTypeTestRunResult extends TType {}
@Model(testManagement.class.TypeTestRunStatus, core.class.Type, DOMAIN_TEST_MANAGEMENT)
@UX(testManagement.string.TestRunStatus)
export class TTypeTestRunStatus extends TType {}
@Model(testManagement.class.TestRunItem, core.class.AttachedDoc, DOMAIN_TEST_MANAGEMENT)
@UX(testManagement.string.TestRunItem)
export class TTestRunItem extends TAttachedDoc implements TestRunItem {
@Prop(TypeRef(testManagement.class.TestRun), testManagement.string.TestRun)
testRun!: Ref<TestRun>
// TODO: Refactor to associations
@Model(testManagement.class.TestResult, core.class.AttachedDoc, DOMAIN_TEST_MANAGEMENT)
@UX(testManagement.string.TestResult)
export class TTestResult extends TAttachedDoc implements TestResult {
@Prop(TypeRef(testManagement.class.TestRun), core.string.AttachedTo)
@Index(IndexKind.Indexed)
declare attachedTo: Ref<TestRun>
@Prop(TypeRef(testManagement.class.TestRun), core.string.AttachedToClass)
@Index(IndexKind.Indexed)
@Hidden()
declare attachedToClass: Ref<Class<TestRun>>
@Prop(TypeRef(testManagement.class.TestProject), core.string.Space)
@Index(IndexKind.Indexed)
@Hidden()
declare space: Ref<TestProject>
@Prop(TypeString(), core.string.Collection)
@Hidden()
override collection: 'results' = 'results'
@Prop(TypeString(), testManagement.string.TestRunName)
@Index(IndexKind.FullText)
name!: string
@Prop(TypeCollaborativeDoc(), testManagement.string.FullDescription)
@Index(IndexKind.FullText)
description!: CollaborativeDoc
@Prop(TypeRef(testManagement.class.TestCase), testManagement.string.TestCase)
testCase!: Ref<TestCase>
@Prop(TypeTestRunResult(), testManagement.string.TestRunResult)
result?: TestRunResult
@Prop(TypeRef(testManagement.class.TestSuite), testManagement.string.TestSuite)
testSuite?: Ref<TestSuite>
@Prop(TypeTestRunStatus(), testManagement.string.TestRunStatus)
status?: TestRunStatus
@Prop(TypeRef(contact.mixin.Employee), testManagement.string.TestAssignee)
assignee?: Ref<Employee>
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files })
attachments?: CollectionSize<Attachment>
@Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments)
comments?: number