Skip to content

Commit dbb3fe6

Browse files
authored
Merge pull request #3252 from codecrafters-io/feat-resizable-test-results-bar
feat(test-results-bar): enable resizable expanded container height
2 parents 03ede09 + ea7e577 commit dbb3fe6

File tree

3 files changed

+43
-28
lines changed

3 files changed

+43
-28
lines changed

app/components/course-page/test-results-bar/index.hbs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<div
22
class="bg-gray-900 border-t border-gray-800 dark flex flex-col items-center {{if this.isExpanded 'rounded-t-lg'}}"
3-
style={{this.containerStyle}}
43
data-test-test-results-bar
54
...attributes
65
>
@@ -18,7 +17,11 @@
1817
</div>
1918
{{/if}}
2019

21-
<div class="relative w-full flex flex-col grow overflow-auto {{unless this.isExpanded 'h-0'}}" data-test-contents>
20+
<div
21+
class="relative w-full flex flex-col grow overflow-auto {{unless this.isResizing 'transition-[height] duration-200 ease-out'}}"
22+
style={{this.expandedContainerStyle}}
23+
data-test-contents
24+
>
2225
{{#if this.isExpanded}}
2326
<CoursePage::TestResultsBar::TopSection
2427
@onCollapseButtonClick={{this.handleCollapseButtonClick}}
@@ -57,5 +60,6 @@
5760
@onCollapseButtonClick={{this.handleCollapseButtonClick}}
5861
@onExpandButtonClick={{this.handleExpandButtonClick}}
5962
class="px-6 w-full"
63+
{{did-insert this.handleDidInsertBottomSectionElement}}
6064
/>
6165
</div>

app/components/course-page/test-results-bar/index.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ export default class TestResultsBar extends Component<Signature> {
2424
@service declare coursePageState: CoursePageStateService;
2525
@service declare authenticator: AuthenticatorService;
2626
@tracked activeTabSlug = 'logs'; // 'logs' | 'autofix'
27-
@tracked customHeight = '75vh';
27+
@tracked bottomSectionElement: HTMLDivElement | null = null;
28+
@tracked expandedContainerHeight = '75vh';
29+
@tracked isResizing = false;
2830

2931
get availableTabSlugs() {
3032
if (this.args.activeStep.type === 'CourseStageStep') {
@@ -44,11 +46,11 @@ export default class TestResultsBar extends Component<Signature> {
4446
}
4547
}
4648

47-
get containerStyle() {
49+
get expandedContainerStyle() {
4850
if (this.isExpanded) {
49-
return htmlSafe(`height: ${this.customHeight}`);
51+
return htmlSafe(`height: ${this.expandedContainerHeight}`);
5052
} else {
51-
return htmlSafe('height: auto');
53+
return htmlSafe('height: 0px');
5254
}
5355
}
5456

@@ -65,28 +67,35 @@ export default class TestResultsBar extends Component<Signature> {
6567
this.coursePageState.testResultsBarIsExpanded = false;
6668
}
6769

70+
@action
71+
handleDidInsertBottomSectionElement(element: HTMLDivElement) {
72+
this.bottomSectionElement = element;
73+
}
74+
6875
@action
6976
handleExpandButtonClick() {
7077
this.coursePageState.testResultsBarIsExpanded = true;
7178
}
7279

7380
@action
7481
handleMouseResize(event: MouseEvent) {
75-
const newHeight = window.innerHeight - event.clientY;
76-
this.customHeight = `max(250px, min(calc(100vh - 20px), ${newHeight}px))`;
82+
const newHeight = window.innerHeight - event.clientY - (this.bottomSectionElement?.offsetHeight || 0);
83+
this.expandedContainerHeight = `max(200px, min(calc(100vh - 50px), ${newHeight}px))`;
7784
}
7885

7986
@action
8087
handleTouchResize(event: TouchEvent) {
8188
const touch = event.touches[0] as Touch;
82-
const newHeight = window.innerHeight - touch.clientY;
83-
this.customHeight = `max(250px, min(calc(100vh - 20px), ${newHeight}px))`;
89+
const newHeight = window.innerHeight - touch.clientY - (this.bottomSectionElement?.offsetHeight || 0);
90+
this.expandedContainerHeight = `max(200px, min(calc(100vh - 50px), ${newHeight}px))`;
8491
}
8592

8693
@action
8794
startResize(event: MouseEvent | TouchEvent) {
8895
event.preventDefault();
8996

97+
this.isResizing = true;
98+
9099
// Trigger mouse resize on left click only
91100
if (event instanceof MouseEvent && event.button === 0) {
92101
document.addEventListener('mousemove', this.handleMouseResize);
@@ -99,12 +108,14 @@ export default class TestResultsBar extends Component<Signature> {
99108

100109
@action
101110
stopMouseResize() {
111+
this.isResizing = false;
102112
document.removeEventListener('mousemove', this.handleMouseResize);
103113
document.removeEventListener('mouseup', this.stopMouseResize);
104114
}
105115

106116
@action
107117
stopTouchResize() {
118+
this.isResizing = false;
108119
document.removeEventListener('touchmove', this.handleTouchResize);
109120
document.removeEventListener('touchend', this.stopTouchResize);
110121
}

tests/acceptance/course-page/test-results-bar/resize-test.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import catalogPage from 'codecrafters-frontend/tests/pages/catalog-page';
22
import courseOverviewPage from 'codecrafters-frontend/tests/pages/course-overview-page';
33
import coursePage from 'codecrafters-frontend/tests/pages/course-page';
4+
import fieldComparator from 'codecrafters-frontend/utils/field-comparator';
45
import testScenario from 'codecrafters-frontend/mirage/scenarios/test';
56
import window from 'ember-window-mock';
67
import { module, test } from 'qunit';
78
import { setupAnimationTest } from 'ember-animated/test-support';
89
import { setupApplicationTest } from 'codecrafters-frontend/tests/helpers';
910
import { setupWindowMock } from 'ember-window-mock/test-support';
1011
import { signIn } from 'codecrafters-frontend/tests/support/authentication-helpers';
11-
import FakeActionCableConsumer from 'codecrafters-frontend/tests/support/fake-action-cable-consumer';
12-
import fieldComparator from 'codecrafters-frontend/utils/field-comparator';
1312

1413
module('Acceptance | course-page | test-results-bar | resize', function (hooks) {
1514
setupApplicationTest(hooks);
@@ -20,9 +19,6 @@ module('Acceptance | course-page | test-results-bar | resize', function (hooks)
2019
testScenario(this.server);
2120
signIn(this.owner, this.server);
2221

23-
const fakeActionCableConsumer = new FakeActionCableConsumer();
24-
this.owner.register('service:action-cable-consumer', fakeActionCableConsumer, { instantiate: false });
25-
2622
let currentUser = this.server.schema.users.first();
2723
let python = this.server.schema.languages.findBy({ name: 'Python' });
2824
let redis = this.server.schema.courses.findBy({ slug: 'redis' });
@@ -42,37 +38,39 @@ module('Acceptance | course-page | test-results-bar | resize', function (hooks)
4238
await catalogPage.clickOnCourse('Build your own Redis');
4339
await courseOverviewPage.clickOnStartCourse();
4440
await coursePage.testResultsBar.clickOnBottomSection();
41+
await new Promise((resolve) => setTimeout(resolve, 200)); // Wait for CSS animation to complete
4542

46-
const desiredHeight = 500;
47-
let testResultsBarHeight = coursePage.testResultsBar.height;
43+
let previousHeight = coursePage.testResultsBar.height;
44+
const desiredHeight = previousHeight - 50;
4845

46+
// Don't know where the +1 comes from, could be border-related
4947
await coursePage.testResultsBar.resizeHandler.mouseDown({ button: 2 });
50-
await coursePage.testResultsBar.resizeHandler.mouseMove({ clientY: window.innerHeight - desiredHeight });
48+
await coursePage.testResultsBar.resizeHandler.mouseMove({ clientY: window.innerHeight - desiredHeight + 1 });
5149
await coursePage.testResultsBar.resizeHandler.mouseUp();
5250

53-
assert.strictEqual(testResultsBarHeight, coursePage.testResultsBar.height, 'Right mouse button should not resize test results bar');
51+
assert.strictEqual(previousHeight, coursePage.testResultsBar.height, 'Right mouse button should not resize test results bar');
5452

53+
// Don't know where the +1 comes from, could be border-related
5554
await coursePage.testResultsBar.resizeHandler.mouseDown({ button: 0 });
56-
await coursePage.testResultsBar.resizeHandler.mouseMove({ clientY: window.innerHeight - desiredHeight });
55+
await coursePage.testResultsBar.resizeHandler.mouseMove({ clientY: window.innerHeight - desiredHeight + 1 });
5756
await coursePage.testResultsBar.resizeHandler.mouseUp();
5857

59-
testResultsBarHeight = coursePage.testResultsBar.height;
60-
assert.strictEqual(testResultsBarHeight, desiredHeight, 'Left mouse button should resize test results bar');
58+
assert.notStrictEqual(previousHeight, coursePage.testResultsBar.height, 'Test results bar should be resized');
59+
assert.strictEqual(desiredHeight, coursePage.testResultsBar.height, 'Left mouse button should resize test results bar');
60+
61+
previousHeight = coursePage.testResultsBar.height;
6162

6263
await coursePage.testResultsBar.clickOnBottomSection();
6364
await coursePage.testResultsBar.clickOnBottomSection();
65+
await new Promise((resolve) => setTimeout(resolve, 200)); // Wait for CSS animation to complete
6466

65-
testResultsBarHeight = coursePage.testResultsBar.height;
66-
assert.strictEqual(testResultsBarHeight, desiredHeight, 'Test results bar maintains the height after closing and expanding again');
67+
assert.strictEqual(previousHeight, coursePage.testResultsBar.height, 'Test results bar maintains the height after closing and expanding again');
6768
});
6869

6970
test('can resize test results bar using touch', async function (assert) {
7071
testScenario(this.server);
7172
signIn(this.owner, this.server);
7273

73-
const fakeActionCableConsumer = new FakeActionCableConsumer();
74-
this.owner.register('service:action-cable-consumer', fakeActionCableConsumer, { instantiate: false });
75-
7674
let currentUser = this.server.schema.users.first();
7775
let python = this.server.schema.languages.findBy({ name: 'Python' });
7876
let redis = this.server.schema.courses.findBy({ slug: 'redis' });
@@ -96,15 +94,17 @@ module('Acceptance | course-page | test-results-bar | resize', function (hooks)
9694

9795
const desiredHeight = 500;
9896

97+
// Don't know where the +1 comes from, could be border-related
9998
await coursePage.testResultsBar.resizeHandler.touchStart();
100-
await coursePage.testResultsBar.resizeHandler.touchMove({ touches: [{ clientY: window.innerHeight - desiredHeight }] });
99+
await coursePage.testResultsBar.resizeHandler.touchMove({ touches: [{ clientY: window.innerHeight - desiredHeight + 1 }] });
101100
await coursePage.testResultsBar.resizeHandler.touchEnd();
102101

103102
let testResultsBarHeight = coursePage.testResultsBar.height;
104103
assert.strictEqual(testResultsBarHeight, desiredHeight, 'Test results bar should be resized using touch');
105104

106105
await coursePage.testResultsBar.clickOnBottomSection();
107106
await coursePage.testResultsBar.clickOnBottomSection();
107+
await new Promise((resolve) => setTimeout(resolve, 200)); // Wait for CSS animation to complete
108108

109109
testResultsBarHeight = coursePage.testResultsBar.height;
110110
assert.strictEqual(testResultsBarHeight, desiredHeight, 'Test results bar maintains the height after closing and expanding again');

0 commit comments

Comments
 (0)