diff --git a/spec/frontend/work_items/components/work_items_list_critical_tests_spec.js b/spec/frontend/work_items/components/work_items_list_critical_tests_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..95893d2fc5a5ff4de8d1e302badfe53f51201fc9
--- /dev/null
+++ b/spec/frontend/work_items/components/work_items_list_critical_tests_spec.js
@@ -0,0 +1,192 @@
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import VueRouter from 'vue-router';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import WorkItemsListApp from '~/work_items/pages/work_items_list_app.vue';
+import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
+import getWorkItemsQuery from 'ee_else_ce/work_items/graphql/list/get_work_items_full.query.graphql';
+import getWorkItemStateCountsQuery from 'ee_else_ce/work_items/graphql/list/get_work_item_state_counts.query.graphql';
+import { createRouter } from '~/work_items/router';
+import { CREATED_DESC } from '~/issues/list/constants';
+import {
+ FILTERED_SEARCH_TERM,
+ OPERATOR_IS,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_LABEL,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+
+Vue.use(VueApollo);
+Vue.use(VueRouter);
+
+describe('WorkItemsListApp - Critical Tests', () => {
+ let wrapper;
+ let mockApollo;
+
+ const mockWorkItemsResponse = {
+ data: {
+ namespace: {
+ id: 'gid://gitlab/Project/1',
+ __typename: 'Project',
+ name: 'Test Project',
+ workItems: {
+ nodes: [],
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: null,
+ __typename: 'PageInfo',
+ },
+ },
+ },
+ },
+ };
+
+ const mockCountsResponse = {
+ data: {
+ namespace: {
+ id: 'gid://gitlab/Project/1',
+ __typename: 'Project',
+ workItemStateCounts: {
+ all: 0,
+ opened: 0,
+ closed: 0,
+ },
+ },
+ },
+ };
+
+ const defaultQueryHandler = jest.fn().mockResolvedValue(mockWorkItemsResponse);
+ const countsQueryHandler = jest.fn().mockResolvedValue(mockCountsResponse);
+
+ const findIssuableList = () => wrapper.findComponent(IssuableList);
+
+ const mountComponent = () => {
+ mockApollo = createMockApollo([
+ [getWorkItemsQuery, defaultQueryHandler],
+ [getWorkItemStateCountsQuery, countsQueryHandler],
+ ]);
+
+ wrapper = shallowMountExtended(WorkItemsListApp, {
+ router: createRouter({ fullPath: '/work_items' }),
+ apolloProvider: mockApollo,
+ provide: {
+ autocompleteAwardEmojisPath: '/autocomplete/award/emojis/path',
+ canBulkUpdate: false,
+ canBulkEditEpics: false,
+ hasBlockedIssuesFeature: false,
+ hasEpicsFeature: false,
+ hasIssuableHealthStatusFeature: false,
+ hasIssueWeightsFeature: false,
+ hasOkrsFeature: false,
+ hasQualityManagementFeature: false,
+ hasCustomFieldsFeature: false,
+ initialSort: CREATED_DESC,
+ isGroup: false,
+ isSignedIn: true,
+ showNewWorkItem: false,
+ fullPath: 'test-project',
+ projectId: 'gid://gitlab/Project/1',
+ },
+ propsData: {
+ rootPageFullPath: 'test-project',
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper?.destroy();
+ });
+
+ describe('Critical filter functionality', () => {
+ it('handles search with special characters correctly', async () => {
+ mountComponent();
+ await waitForPromises(); // Wait for initial mount query
+
+ // Emit filter event on IssuableList with special characters in search
+ findIssuableList().vm.$emit('filter', [
+ {
+ type: FILTERED_SEARCH_TERM,
+ value: {
+ data: '"exact phrase" AND (bug OR feature)',
+ operator: 'undefined',
+ },
+ },
+ ]);
+ await nextTick();
+
+ // Verify query was called with the search term
+ expect(defaultQueryHandler).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ search: '"exact phrase" AND (bug OR feature)',
+ }),
+ );
+ });
+
+ it('filters for unassigned items correctly', async () => {
+ mountComponent();
+ await waitForPromises(); // Wait for initial mount query
+
+ // Emit filter event for unassigned items
+ findIssuableList().vm.$emit('filter', [
+ {
+ type: TOKEN_TYPE_ASSIGNEE,
+ value: {
+ data: 'None', // Special value for unassigned
+ operator: OPERATOR_IS,
+ },
+ },
+ ]);
+ await nextTick();
+
+ // Verify query was called with unassigned filter
+ expect(defaultQueryHandler).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ assigneeUsername: 'None',
+ }),
+ );
+ });
+
+ it('combines search with multiple filters correctly', async () => {
+ mountComponent();
+ await waitForPromises(); // Wait for initial mount query
+
+ // Emit filter event with search term and multiple filters
+ findIssuableList().vm.$emit('filter', [
+ {
+ type: FILTERED_SEARCH_TERM,
+ value: {
+ data: 'regression bug',
+ operator: 'undefined',
+ },
+ },
+ {
+ type: TOKEN_TYPE_ASSIGNEE,
+ value: {
+ data: 'None',
+ operator: OPERATOR_IS,
+ },
+ },
+ {
+ type: TOKEN_TYPE_LABEL,
+ value: {
+ data: 'critical',
+ operator: OPERATOR_IS,
+ },
+ },
+ ]);
+ await nextTick();
+
+ // Verify query was called with combined filters
+ expect(defaultQueryHandler).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ search: 'regression bug',
+ assigneeUsername: 'None',
+ labelNames: 'critical',
+ }),
+ );
+ });
+ });
+});
diff --git a/spec/frontend/work_items/components/work_items_list_empty_states_spec.js b/spec/frontend/work_items/components/work_items_list_empty_states_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ace81ceb050ff6040a8736d04caed512cd45f4e
--- /dev/null
+++ b/spec/frontend/work_items/components/work_items_list_empty_states_spec.js
@@ -0,0 +1,159 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import VueRouter from 'vue-router';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import WorkItemsListApp from '~/work_items/pages/work_items_list_app.vue';
+import getWorkItemsQuery from 'ee_else_ce/work_items/graphql/list/get_work_items_full.query.graphql';
+import { createRouter } from '~/work_items/router';
+import { defaultProvide, mockWorkItemsResponse } from './work_items_list_test_helpers';
+
+Vue.use(VueApollo);
+Vue.use(VueRouter);
+
+describe('WorkItemsListApp - Empty States', () => {
+ let wrapper;
+ let mockApollo;
+ const mockQueryHandler = jest.fn().mockResolvedValue(mockWorkItemsResponse);
+
+ const createComponent = ({ searchQuery = '', filters = {}, provide = {} } = {}) => {
+ mockApollo = createMockApollo([[getWorkItemsQuery, mockQueryHandler]]);
+ wrapper = shallowMount(WorkItemsListApp, {
+ router: createRouter({ fullPath: '/work_items' }),
+ apolloProvider: mockApollo,
+ propsData: {
+ rootPageFullPath: 'test-project',
+ searchQuery,
+ filters,
+ },
+ provide: {
+ ...defaultProvide,
+ fullPath: 'test-project',
+ ...provide,
+ },
+ });
+ };
+
+ afterEach(() => wrapper?.destroy());
+
+ describe('Empty value filtering', () => {
+ it('filters for unassigned items only', async () => {
+ createComponent({ filters: { assigneeId: 'unassigned' } });
+ await waitForPromises(); // Wait for initial mount query
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ assigneeId: 'unassigned' }),
+ );
+ });
+
+ it('filters for items with no labels', async () => {
+ createComponent({ filters: { labelNames: ['none'] } });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ labelNames: ['none'] }),
+ );
+ });
+
+ it('filters for items with no milestone', async () => {
+ createComponent({ filters: { milestoneTitle: 'none' } });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ milestoneTitle: 'none' }),
+ );
+ });
+
+ it('filters for items with empty description', async () => {
+ createComponent({ filters: { descriptionEmpty: true } });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ descriptionEmpty: true }),
+ );
+ });
+
+ it('filters for completely empty work items', async () => {
+ createComponent({
+ filters: {
+ assigneeId: 'unassigned',
+ labelNames: ['none'],
+ milestoneTitle: 'none',
+ descriptionEmpty: true,
+ },
+ });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({
+ assigneeId: 'unassigned',
+ labelNames: ['none'],
+ milestoneTitle: 'none',
+ descriptionEmpty: true,
+ }),
+ );
+ });
+
+ it('switches from any to none filters', async () => {
+ createComponent({ filters: { labelNames: ['any'] } });
+ await waitForPromises();
+
+ await wrapper.setProps({ filters: { labelNames: ['none'] } });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenLastCalledWith(
+ expect.objectContaining({ labelNames: ['none'] }),
+ );
+ });
+
+ it('combines empty filters with search', async () => {
+ createComponent({
+ searchQuery: 'TODO',
+ filters: { assigneeId: 'unassigned', descriptionEmpty: true },
+ });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({
+ searchTerm: 'TODO',
+ assigneeId: 'unassigned',
+ descriptionEmpty: true,
+ }),
+ );
+ });
+
+ it('handles multiple assignees with unassigned', async () => {
+ createComponent({
+ filters: { assigneeUsernames: ['user1'], assigneeId: 'unassigned' },
+ });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({
+ assigneeUsernames: ['user1'],
+ assigneeId: 'unassigned',
+ }),
+ );
+ });
+
+ it('combines multiple empty value filters', async () => {
+ createComponent({
+ filters: {
+ assigneeId: 'unassigned',
+ labelNames: ['none'],
+ milestoneTitle: 'none',
+ },
+ });
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({
+ assigneeId: 'unassigned',
+ labelNames: ['none'],
+ milestoneTitle: 'none',
+ }),
+ );
+ });
+ });
+});
diff --git a/spec/frontend/work_items/components/work_items_list_performance_spec.js b/spec/frontend/work_items/components/work_items_list_performance_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..c582effc81c028f93eaee7f73f9ebba092d51a0e
--- /dev/null
+++ b/spec/frontend/work_items/components/work_items_list_performance_spec.js
@@ -0,0 +1,121 @@
+import { GlSearchBoxByType, GlAlert } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import VueRouter from 'vue-router';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import WorkItemsListApp from '~/work_items/pages/work_items_list_app.vue';
+import getWorkItemsQuery from 'ee_else_ce/work_items/graphql/list/get_work_items_full.query.graphql';
+import { createRouter } from '~/work_items/router';
+import { defaultProvide, mockWorkItemsResponse } from './work_items_list_test_helpers';
+
+Vue.use(VueApollo);
+Vue.use(VueRouter);
+
+describe('WorkItemsListApp - Performance & Edge Cases', () => {
+ let wrapper;
+ let mockApollo;
+ const mockQueryHandler = jest.fn().mockResolvedValue(mockWorkItemsResponse);
+
+ const createComponent = ({ workItemsQueryHandler = mockQueryHandler, provide = {} } = {}) => {
+ mockApollo = createMockApollo([[getWorkItemsQuery, workItemsQueryHandler]]);
+ wrapper = shallowMount(WorkItemsListApp, {
+ router: createRouter({ fullPath: '/work_items' }),
+ apolloProvider: mockApollo,
+ propsData: {
+ rootPageFullPath: 'test-project',
+ },
+ provide: {
+ ...defaultProvide,
+ fullPath: 'test-project',
+ ...provide,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper?.destroy();
+ jest.clearAllTimers();
+ });
+
+ describe('Performance scenarios', () => {
+ it('handles 1000+ search results', async () => {
+ const largeDataset = Array.from({ length: 1500 }, (_, i) => ({
+ id: `gid://gitlab/WorkItem/${i}`,
+ title: `Item ${i}`,
+ }));
+
+ const largeHandler = jest.fn().mockResolvedValue({
+ data: {
+ workspace: {
+ workItems: {
+ nodes: largeDataset,
+ pageInfo: { hasNextPage: true },
+ },
+ },
+ },
+ });
+
+ createComponent({ workItemsQueryHandler: largeHandler });
+ await waitForPromises(); // Wait for initial mount query
+
+ expect(largeHandler).toHaveBeenCalled();
+ });
+
+ it('debounces rapid search typing', async () => {
+ jest.useFakeTimers();
+ createComponent();
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+
+ ['t', 'te', 'tes', 'test'].forEach((text) => {
+ searchBox.vm.$emit('input', text);
+ });
+
+ expect(mockQueryHandler).toHaveBeenCalledTimes(1);
+
+ jest.advanceTimersByTime(300);
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledTimes(2);
+ jest.useRealTimers();
+ });
+
+ it('handles network timeout gracefully', async () => {
+ const timeoutHandler = jest.fn().mockRejectedValue(new Error('Network timeout'));
+ createComponent({ workItemsQueryHandler: timeoutHandler });
+
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', 'timeout test');
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlAlert).exists()).toBe(true);
+ });
+
+ it('handles GraphQL errors correctly', async () => {
+ const errorHandler = jest.fn().mockRejectedValue({
+ errors: [{ message: 'GraphQL error' }],
+ });
+
+ createComponent({ workItemsQueryHandler: errorHandler });
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlAlert).exists()).toBe(true);
+ });
+
+ it('handles permission changes mid-session', async () => {
+ createComponent();
+ await waitForPromises();
+
+ mockQueryHandler.mockRejectedValueOnce({
+ errors: [{ message: 'Forbidden', extensions: { code: 'FORBIDDEN' } }],
+ });
+
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', 'restricted');
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlAlert).exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/work_items/components/work_items_list_search_filters_spec.js b/spec/frontend/work_items/components/work_items_list_search_filters_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..a9e331d2afecbe75d55837d26fb03c3b3755a794
--- /dev/null
+++ b/spec/frontend/work_items/components/work_items_list_search_filters_spec.js
@@ -0,0 +1,253 @@
+import { GlSearchBoxByType } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import VueRouter from 'vue-router';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import WorkItemsListApp from '~/work_items/pages/work_items_list_app.vue';
+import getWorkItemsQuery from 'ee_else_ce/work_items/graphql/list/get_work_items_full.query.graphql';
+import { createRouter } from '~/work_items/router';
+import { defaultProvide, mockWorkItemsResponse } from './work_items_list_test_helpers';
+
+Vue.use(VueApollo);
+Vue.use(VueRouter);
+
+describe('WorkItemsListApp - Search and Filters', () => {
+ let wrapper;
+ let mockApollo;
+ const mockQueryHandler = jest.fn().mockResolvedValue(mockWorkItemsResponse);
+
+ const createComponent = ({ searchQuery = '', filters = {}, provide = {} } = {}) => {
+ mockApollo = createMockApollo([[getWorkItemsQuery, mockQueryHandler]]);
+ wrapper = shallowMount(WorkItemsListApp, {
+ router: createRouter({ fullPath: '/work_items' }),
+ apolloProvider: mockApollo,
+ propsData: {
+ rootPageFullPath: 'test-project',
+ searchQuery,
+ filters,
+ },
+ provide: {
+ ...defaultProvide,
+ fullPath: 'test-project',
+ ...provide,
+ },
+ });
+ };
+
+ afterEach(() => wrapper?.destroy());
+
+ describe('Search functionality', () => {
+ it('handles exact phrase search with quotes', async () => {
+ createComponent();
+ await waitForPromises(); // Wait for initial mount query
+
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', '"exact phrase"');
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ searchTerm: '"exact phrase"' }),
+ );
+ });
+
+ it('handles wildcard pattern matching', async () => {
+ createComponent();
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', '*bug*');
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ searchTerm: '*bug*' }),
+ );
+ });
+
+ it('handles boolean operators', async () => {
+ createComponent();
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', 'epic AND (bug OR feature)');
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ searchTerm: 'epic AND (bug OR feature)' }),
+ );
+ });
+
+ it('handles escape sequences', async () => {
+ createComponent();
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', '\\[blocked\\]');
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ searchTerm: '\\[blocked\\]' }),
+ );
+ });
+
+ it('handles Unicode and emoji', async () => {
+ createComponent();
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', '🐛 工作 bug');
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ searchTerm: '🐛 工作 bug' }),
+ );
+ });
+
+ it('sanitizes XSS attempts', async () => {
+ createComponent();
+ const searchBox = wrapper.findComponent(GlSearchBoxByType);
+ searchBox.vm.$emit('input', '');
+ await waitForPromises();
+
+ expect(mockQueryHandler).toHaveBeenCalledWith(
+ expect.objectContaining({ searchTerm: '' }),
+ );
+ expect(wrapper.html()).not.toContain('