node-pandas 1.0.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.kiro/agents/git-committer-agent.md +208 -0
- package/.kiro/agents/npm-publisher-agent.md +501 -0
- package/.kiro/publish-status-2.0.0.md +134 -0
- package/.kiro/published-versions.md +11 -0
- package/.kiro/specs/pandas-like-enhancements/.config.kiro +1 -0
- package/.kiro/specs/pandas-like-enhancements/design.md +377 -0
- package/.kiro/specs/pandas-like-enhancements/requirements.md +257 -0
- package/.kiro/specs/pandas-like-enhancements/tasks.md +477 -0
- package/CHANGELOG.md +42 -0
- package/README.md +243 -0
- package/TESTING_SETUP.md +183 -0
- package/jest.config.js +25 -0
- package/package.json +11 -3
- package/src/bases/CsvBase.js +4 -13
- package/src/dataframe/dataframe.js +595 -66
- package/src/features/GroupBy.js +561 -0
- package/src/features/dateRange.js +106 -0
- package/src/index.js +6 -1
- package/src/series/series.js +688 -46
- package/src/utils/errors.js +314 -0
- package/src/utils/logger.js +259 -0
- package/src/utils/typeDetection.js +339 -0
- package/src/utils/utils.js +5 -1
- package/src/utils/validation.js +450 -0
- package/tests/README.md +151 -0
- package/tests/integration/.gitkeep +0 -0
- package/tests/integration/README.md +3 -0
- package/tests/property/.gitkeep +0 -0
- package/tests/property/README.md +3 -0
- package/tests/setup.js +16 -0
- package/tests/test.js +2 -1
- package/tests/unit/.gitkeep +0 -0
- package/tests/unit/README.md +3 -0
- package/tests/unit/dataframe.test.js +1141 -0
- package/tests/unit/example.test.js +23 -0
- package/tests/unit/series.test.js +441 -0
- package/tests/unit/tocsv.test.js +838 -0
- package/tests/utils/testAssertions.js +143 -0
- package/tests/utils/testDataGenerator.js +123 -0
package/README.md
CHANGED
|
@@ -43,6 +43,12 @@ An [npm package](https://www.npmjs.com/package/node-pandas) that incorporates mi
|
|
|
43
43
|
|
|
44
44
|
4. [Example 4 - Accessing columns (Retrieving columns using column name)](#df-ex4) - `df.fullName -> ["R A", "B R", "P K"]`
|
|
45
45
|
|
|
46
|
+
5. [Example 5 - Selecting specific columns using select()](#df-ex5)
|
|
47
|
+
|
|
48
|
+
6. [Example 6 - Filtering DataFrame rows using filter()](#df-ex6)
|
|
49
|
+
|
|
50
|
+
7. [Example 7 - Grouping and aggregating data using groupBy()](#df-ex7)
|
|
51
|
+
|
|
46
52
|
<hr>
|
|
47
53
|
|
|
48
54
|
## Getting started
|
|
@@ -426,6 +432,243 @@ for(let profession of professions) {
|
|
|
426
432
|
|
|
427
433
|
<hr>
|
|
428
434
|
|
|
435
|
+
<h3 id='df-ex5'><code>Example 5 - Selecting specific columns using select()</code></h3>
|
|
436
|
+
|
|
437
|
+
> **Note:** The `select()` method returns a new DataFrame containing only the specified columns.
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
const pd = require("node-pandas")
|
|
441
|
+
|
|
442
|
+
// Create a DataFrame with employee data
|
|
443
|
+
const df = pd.DataFrame([
|
|
444
|
+
['Rishikesh Agrawani', 32, 'Engineering'],
|
|
445
|
+
['Hemkesh Agrawani', 30, 'Marketing'],
|
|
446
|
+
['Malinikesh Agrawani', 28, 'Sales']
|
|
447
|
+
], ['name', 'age', 'department'])
|
|
448
|
+
|
|
449
|
+
df.show
|
|
450
|
+
/*
|
|
451
|
+
┌─────────┬──────────────────────┬─────┬──────────────┐
|
|
452
|
+
│ (index) │ name │ age │ department │
|
|
453
|
+
├─────────┼──────────────────────┼─────┼──────────────┤
|
|
454
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │ 'Engineering'│
|
|
455
|
+
│ 1 │ 'Hemkesh Agrawani' │ 30 │ 'Marketing' │
|
|
456
|
+
│ 2 │ 'Malinikesh Agrawani'│ 28 │ 'Sales' │
|
|
457
|
+
└─────────┴──────────────────────┴─────┴──────────────┘
|
|
458
|
+
*/
|
|
459
|
+
|
|
460
|
+
// Select a single column
|
|
461
|
+
const nameOnly = df.select(['name'])
|
|
462
|
+
nameOnly.show
|
|
463
|
+
/*
|
|
464
|
+
┌─────────┬──────────────────────┐
|
|
465
|
+
│ (index) │ name │
|
|
466
|
+
├─────────┼──────────────────────┤
|
|
467
|
+
│ 0 │ 'Rishikesh Agrawani' │
|
|
468
|
+
│ 1 │ 'Hemkesh Agrawani' │
|
|
469
|
+
│ 2 │ 'Malinikesh Agrawani'│
|
|
470
|
+
└─────────┴──────────────────────┘
|
|
471
|
+
*/
|
|
472
|
+
|
|
473
|
+
// Select multiple columns
|
|
474
|
+
const nameAndAge = df.select(['name', 'age'])
|
|
475
|
+
nameAndAge.show
|
|
476
|
+
/*
|
|
477
|
+
┌─────────┬──────────────────────┬─────┐
|
|
478
|
+
│ (index) │ name │ age │
|
|
479
|
+
├─────────┼──────────────────────┼─────┤
|
|
480
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │
|
|
481
|
+
│ 1 │ 'Hemkesh Agrawani' │ 30 │
|
|
482
|
+
│ 2 │ 'Malinikesh Agrawani'│ 28 │
|
|
483
|
+
└─────────┴──────────────────────┴─────┘
|
|
484
|
+
*/
|
|
485
|
+
|
|
486
|
+
// Original DataFrame remains unchanged
|
|
487
|
+
console.log(df.columns) // ['name', 'age', 'department']
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
<hr>
|
|
491
|
+
|
|
492
|
+
<h3 id='df-ex6'><code>Example 6 - Filtering DataFrame rows using filter()</code></h3>
|
|
493
|
+
|
|
494
|
+
> **Note:** The `filter()` method returns a new DataFrame containing only rows that match the condition. Multiple filters can be chained together.
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
const pd = require("node-pandas")
|
|
498
|
+
|
|
499
|
+
// Create a DataFrame with employee data
|
|
500
|
+
const df = pd.DataFrame([
|
|
501
|
+
['Rishikesh Agrawani', 32, 'Engineering'],
|
|
502
|
+
['Hemkesh Agrawani', 30, 'Marketing'],
|
|
503
|
+
['Malinikesh Agrawani', 28, 'Sales']
|
|
504
|
+
], ['name', 'age', 'department'])
|
|
505
|
+
|
|
506
|
+
df.show
|
|
507
|
+
/*
|
|
508
|
+
┌─────────┬──────────────────────┬─────┬──────────────┐
|
|
509
|
+
│ (index) │ name │ age │ department │
|
|
510
|
+
├─────────┼──────────────────────┼─────┼──────────────┤
|
|
511
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │ 'Engineering'│
|
|
512
|
+
│ 1 │ 'Hemkesh Agrawani' │ 30 │ 'Marketing' │
|
|
513
|
+
│ 2 │ 'Malinikesh Agrawani'│ 28 │ 'Sales' │
|
|
514
|
+
└─────────┴──────────────────────┴─────┴──────────────┘
|
|
515
|
+
*/
|
|
516
|
+
|
|
517
|
+
// Filter rows where age is greater than 28
|
|
518
|
+
const over28 = df.filter(row => row.age > 28)
|
|
519
|
+
over28.show
|
|
520
|
+
/*
|
|
521
|
+
┌─────────┬──────────────────────┬─────┬──────────────┐
|
|
522
|
+
│ (index) │ name │ age │ department │
|
|
523
|
+
├─────────┼──────────────────────┼─────┼──────────────┤
|
|
524
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │ 'Engineering'│
|
|
525
|
+
│ 1 │ 'Hemkesh Agrawani' │ 30 │ 'Marketing' │
|
|
526
|
+
└─────────┴──────────────────────┴─────┴──────────────┘
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
// Filter rows where department is 'Engineering'
|
|
530
|
+
const engineering = df.filter(row => row.department === 'Engineering')
|
|
531
|
+
engineering.show
|
|
532
|
+
/*
|
|
533
|
+
┌─────────┬──────────────────────┬─────┬──────────────┐
|
|
534
|
+
│ (index) │ name │ age │ department │
|
|
535
|
+
├─────────┼──────────────────────┼─────┼──────────────┤
|
|
536
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │ 'Engineering'│
|
|
537
|
+
└─────────┴──────────────────────┴─────┴──────────────┘
|
|
538
|
+
*/
|
|
539
|
+
|
|
540
|
+
// Chain multiple filters together
|
|
541
|
+
const result = df
|
|
542
|
+
.filter(row => row.age > 28)
|
|
543
|
+
.filter(row => row.department !== 'Sales')
|
|
544
|
+
result.show
|
|
545
|
+
/*
|
|
546
|
+
┌─────────┬──────────────────────┬─────┬──────────────┐
|
|
547
|
+
│ (index) │ name │ age │ department │
|
|
548
|
+
├─────────┼──────────────────────┼─────┼──────────────┤
|
|
549
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │ 'Engineering'│
|
|
550
|
+
│ 1 │ 'Hemkesh Agrawani' │ 30 │ 'Marketing' │
|
|
551
|
+
└─────────┴──────────────────────┴─────┴──────────────┘
|
|
552
|
+
*/
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
<hr>
|
|
556
|
+
|
|
557
|
+
<h3 id='df-ex7'><code>Example 7 - Grouping and aggregating data using groupBy()</code></h3>
|
|
558
|
+
|
|
559
|
+
> **Note:** The `groupBy()` method groups rows by one or more columns and allows aggregation using methods like `mean()`, `sum()`, `count()`, `min()`, and `max()`.
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
const pd = require("node-pandas")
|
|
563
|
+
|
|
564
|
+
// Create a DataFrame with employee data including departments
|
|
565
|
+
const df = pd.DataFrame([
|
|
566
|
+
['Rishikesh Agrawani', 32, 'Engineering', 95000],
|
|
567
|
+
['Hemkesh Agrawani', 30, 'Marketing', 75000],
|
|
568
|
+
['Malinikesh Agrawani', 28, 'Sales', 65000],
|
|
569
|
+
['Alice Johnson', 29, 'Engineering', 92000],
|
|
570
|
+
['Bob Smith', 31, 'Marketing', 78000],
|
|
571
|
+
['Carol White', 27, 'Sales', 62000]
|
|
572
|
+
], ['name', 'age', 'department', 'salary'])
|
|
573
|
+
|
|
574
|
+
df.show
|
|
575
|
+
/*
|
|
576
|
+
┌─────────┬──────────────────────┬─────┬──────────────┬────────┐
|
|
577
|
+
│ (index) │ name │ age │ department │ salary │
|
|
578
|
+
├─────────┼──────────────────────┼─────┼──────────────┼────────┤
|
|
579
|
+
│ 0 │ 'Rishikesh Agrawani' │ 32 │ 'Engineering'│ 95000 │
|
|
580
|
+
│ 1 │ 'Hemkesh Agrawani' │ 30 │ 'Marketing' │ 75000 │
|
|
581
|
+
│ 2 │ 'Malinikesh Agrawani'│ 28 │ 'Sales' │ 65000 │
|
|
582
|
+
│ 3 │ 'Alice Johnson' │ 29 │ 'Engineering'│ 92000 │
|
|
583
|
+
│ 4 │ 'Bob Smith' │ 31 │ 'Marketing' │ 78000 │
|
|
584
|
+
│ 5 │ 'Carol White' │ 27 │ 'Sales' │ 62000 │
|
|
585
|
+
└─────────┴──────────────────────┴─────┴──────────────┴────────┘
|
|
586
|
+
*/
|
|
587
|
+
|
|
588
|
+
// Single-column grouping: Group by department and calculate mean salary
|
|
589
|
+
const avgSalaryByDept = df.groupBy('department').mean('salary')
|
|
590
|
+
avgSalaryByDept.show
|
|
591
|
+
/*
|
|
592
|
+
┌─────────┬──────────────┬──────────────┐
|
|
593
|
+
│ (index) │ department │ salary_mean │
|
|
594
|
+
├─────────┼──────────────┼──────────────┤
|
|
595
|
+
│ 0 │ 'Engineering'│ 93500 │
|
|
596
|
+
│ 1 │ 'Marketing' │ 76500 │
|
|
597
|
+
│ 2 │ 'Sales' │ 63500 │
|
|
598
|
+
└─────────┴──────────────┴──────────────┘
|
|
599
|
+
*/
|
|
600
|
+
|
|
601
|
+
// Group by department and calculate sum of salaries
|
|
602
|
+
const totalSalaryByDept = df.groupBy('department').sum('salary')
|
|
603
|
+
totalSalaryByDept.show
|
|
604
|
+
/*
|
|
605
|
+
┌─────────┬──────────────┬──────────────┐
|
|
606
|
+
│ (index) │ department │ salary_sum │
|
|
607
|
+
├─────────┼──────────────┼──────────────┤
|
|
608
|
+
│ 0 │ 'Engineering'│ 187000 │
|
|
609
|
+
│ 1 │ 'Marketing' │ 153000 │
|
|
610
|
+
│ 2 │ 'Sales' │ 127000 │
|
|
611
|
+
└─────────┴──────────────┴──────────────┘
|
|
612
|
+
*/
|
|
613
|
+
|
|
614
|
+
// Group by department and count employees
|
|
615
|
+
const countByDept = df.groupBy('department').count()
|
|
616
|
+
countByDept.show
|
|
617
|
+
/*
|
|
618
|
+
┌─────────┬──────────────┬───────┐
|
|
619
|
+
│ (index) │ department │ count │
|
|
620
|
+
├─────────┼──────────────┼───────┤
|
|
621
|
+
│ 0 │ 'Engineering'│ 2 │
|
|
622
|
+
│ 1 │ 'Marketing' │ 2 │
|
|
623
|
+
│ 2 │ 'Sales' │ 2 │
|
|
624
|
+
└─────────┴──────────────┴───────┘
|
|
625
|
+
*/
|
|
626
|
+
|
|
627
|
+
// Group by department and find minimum age
|
|
628
|
+
const minAgeByDept = df.groupBy('department').min('age')
|
|
629
|
+
minAgeByDept.show
|
|
630
|
+
/*
|
|
631
|
+
┌─────────┬──────────────┬──────────┐
|
|
632
|
+
│ (index) │ department │ age_min │
|
|
633
|
+
├─────────┼──────────────┼──────────┤
|
|
634
|
+
│ 0 │ 'Engineering'│ 29 │
|
|
635
|
+
│ 1 │ 'Marketing' │ 30 │
|
|
636
|
+
│ 2 │ 'Sales' │ 27 │
|
|
637
|
+
└─────────┴──────────────┴──────────┘
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
// Group by department and find maximum age
|
|
641
|
+
const maxAgeByDept = df.groupBy('department').max('age')
|
|
642
|
+
maxAgeByDept.show
|
|
643
|
+
/*
|
|
644
|
+
┌─────────┬──────────────┬──────────┐
|
|
645
|
+
│ (index) │ department │ age_max │
|
|
646
|
+
├─────────┼──────────────┼──────────┤
|
|
647
|
+
│ 0 │ 'Engineering'│ 32 │
|
|
648
|
+
│ 1 │ 'Marketing' │ 31 │
|
|
649
|
+
│ 2 │ 'Sales' │ 28 │
|
|
650
|
+
└─────────┴──────────────┴──────────┘
|
|
651
|
+
*/
|
|
652
|
+
|
|
653
|
+
// Multi-column grouping: Group by department and age range
|
|
654
|
+
const groupedByDeptAndAge = df.groupBy(['department', 'age']).count()
|
|
655
|
+
groupedByDeptAndAge.show
|
|
656
|
+
/*
|
|
657
|
+
┌─────────┬──────────────┬─────┬───────┐
|
|
658
|
+
│ (index) │ department │ age │ count │
|
|
659
|
+
├─────────┼──────────────┼─────┼───────┤
|
|
660
|
+
│ 0 │ 'Engineering'│ 29 │ 1 │
|
|
661
|
+
│ 1 │ 'Engineering'│ 32 │ 1 │
|
|
662
|
+
│ 2 │ 'Marketing' │ 30 │ 1 │
|
|
663
|
+
│ 3 │ 'Marketing' │ 31 │ 1 │
|
|
664
|
+
│ 4 │ 'Sales' │ 27 │ 1 │
|
|
665
|
+
│ 5 │ 'Sales' │ 28 │ 1 │
|
|
666
|
+
└─────────┴──────────────┴─────┴───────┘
|
|
667
|
+
*/
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
<hr>
|
|
671
|
+
|
|
429
672
|
### References
|
|
430
673
|
|
|
431
674
|
+ [Node's util](https://millermedeiros.github.io/mdoc/examples/node_api/doc/util.html)
|
package/TESTING_SETUP.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Testing Infrastructure Setup - Complete
|
|
2
|
+
|
|
3
|
+
This document summarizes the testing infrastructure setup for the node-pandas library.
|
|
4
|
+
|
|
5
|
+
## What Was Set Up
|
|
6
|
+
|
|
7
|
+
### 1. Testing Framework: Jest
|
|
8
|
+
- **Framework**: Jest 29.7.0
|
|
9
|
+
- **Environment**: Node.js
|
|
10
|
+
- **Configuration**: `jest.config.js`
|
|
11
|
+
- **Features**:
|
|
12
|
+
- Zero-config setup
|
|
13
|
+
- Built-in assertion library
|
|
14
|
+
- Code coverage reporting with Istanbul/nyc
|
|
15
|
+
- Watch mode for development
|
|
16
|
+
- Snapshot testing support
|
|
17
|
+
|
|
18
|
+
### 2. Directory Structure
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
tests/
|
|
22
|
+
├── unit/ # Unit tests for individual functions
|
|
23
|
+
├── integration/ # Integration tests for workflows
|
|
24
|
+
├── property/ # Property-based tests
|
|
25
|
+
├── utils/
|
|
26
|
+
│ ├── testDataGenerator.js # Sample data generation utilities
|
|
27
|
+
│ └── testAssertions.js # Custom assertion utilities
|
|
28
|
+
├── setup.js # Test environment setup
|
|
29
|
+
└── README.md # Testing documentation
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 3. Test Utilities
|
|
33
|
+
|
|
34
|
+
#### Test Data Generator (`tests/utils/testDataGenerator.js`)
|
|
35
|
+
Provides functions to generate sample data:
|
|
36
|
+
- `generateNumericArray()` - Numeric arrays
|
|
37
|
+
- `generateMixedArray()` - Mixed-type arrays
|
|
38
|
+
- `generate2DArray()` - 2D arrays for DataFrames
|
|
39
|
+
- `generateDataFrameData()` - Sample DataFrame data
|
|
40
|
+
- `generateCategoricalData()` - Data with categories
|
|
41
|
+
- `generateDataWithNulls()` - Data with null values
|
|
42
|
+
- `generateMergeData()` - Datasets for merge operations
|
|
43
|
+
|
|
44
|
+
#### Test Assertions (`tests/utils/testAssertions.js`)
|
|
45
|
+
Custom assertion utilities:
|
|
46
|
+
- `assertArrayEqual()` - Array equality
|
|
47
|
+
- `assertNumeric()` - Numeric type checking
|
|
48
|
+
- `assertString()` - String type checking
|
|
49
|
+
- `assertNullish()` - Null/undefined checking
|
|
50
|
+
- `assertApproximatelyEqual()` - Numeric approximation
|
|
51
|
+
- `assertInstanceOf()` - Instance type checking
|
|
52
|
+
- `assertHasProperties()` - Object property checking
|
|
53
|
+
- `assert2DArrayDimensions()` - 2D array dimension checking
|
|
54
|
+
|
|
55
|
+
### 4. Package.json Scripts
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"test": "jest",
|
|
60
|
+
"test:watch": "jest --watch",
|
|
61
|
+
"test:coverage": "jest --coverage",
|
|
62
|
+
"test:unit": "jest tests/unit",
|
|
63
|
+
"test:integration": "jest tests/integration",
|
|
64
|
+
"test:property": "jest tests/property"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 5. Coverage Configuration
|
|
69
|
+
|
|
70
|
+
- **Threshold**: 80% for all metrics (statements, branches, functions, lines)
|
|
71
|
+
- **Coverage Report**: Generated in `coverage/` directory
|
|
72
|
+
- **Excluded**: `src/index.js`, `src/messages/**`
|
|
73
|
+
|
|
74
|
+
### 6. Test Setup
|
|
75
|
+
|
|
76
|
+
- **Setup File**: `tests/setup.js`
|
|
77
|
+
- **Environment**: `NODE_ENV=test`
|
|
78
|
+
- **Test Pattern**: `**/tests/**/*.test.js`
|
|
79
|
+
|
|
80
|
+
## How to Use
|
|
81
|
+
|
|
82
|
+
### Run All Tests
|
|
83
|
+
```bash
|
|
84
|
+
npm test
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Run Tests in Watch Mode
|
|
88
|
+
```bash
|
|
89
|
+
npm run test:watch
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Generate Coverage Report
|
|
93
|
+
```bash
|
|
94
|
+
npm run test:coverage
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Run Specific Test Suites
|
|
98
|
+
```bash
|
|
99
|
+
npm run test:unit # Unit tests only
|
|
100
|
+
npm run test:integration # Integration tests only
|
|
101
|
+
npm run test:property # Property-based tests only
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Writing Tests
|
|
105
|
+
|
|
106
|
+
### Unit Test Example
|
|
107
|
+
```javascript
|
|
108
|
+
// tests/unit/series.test.js
|
|
109
|
+
const { Series } = require('../../src/series/series');
|
|
110
|
+
const { generateNumericArray } = require('../utils/testDataGenerator');
|
|
111
|
+
|
|
112
|
+
describe('Series', () => {
|
|
113
|
+
test('creates a Series with array data', () => {
|
|
114
|
+
const data = generateNumericArray(5);
|
|
115
|
+
const s = new Series(data);
|
|
116
|
+
expect(s.length).toBe(5);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Property Test Example
|
|
122
|
+
```javascript
|
|
123
|
+
// tests/property/series.test.js
|
|
124
|
+
const { Series } = require('../../src/series/series');
|
|
125
|
+
|
|
126
|
+
describe('Property: Series Creation Preserves Array Elements', () => {
|
|
127
|
+
test('validates property for various inputs', () => {
|
|
128
|
+
// Test across many inputs
|
|
129
|
+
for (let i = 1; i <= 100; i++) {
|
|
130
|
+
const data = Array.from({ length: i }, (_, j) => j);
|
|
131
|
+
const s = new Series(data);
|
|
132
|
+
expect(s.length).toBe(i);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Verification
|
|
139
|
+
|
|
140
|
+
The setup has been verified with an example test:
|
|
141
|
+
```bash
|
|
142
|
+
$ npm test
|
|
143
|
+
|
|
144
|
+
PASS tests/unit/example.test.js
|
|
145
|
+
Testing Infrastructure Setup
|
|
146
|
+
✓ Jest is configured correctly
|
|
147
|
+
✓ Test utilities can be imported
|
|
148
|
+
✓ Assertion utilities can be imported
|
|
149
|
+
|
|
150
|
+
Test Suites: 1 passed, 1 total
|
|
151
|
+
Tests: 3 passed, 3 total
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Next Steps
|
|
155
|
+
|
|
156
|
+
1. Write unit tests for Series class (Task 4.10)
|
|
157
|
+
2. Write unit tests for DataFrame class (Task 6.4, 6.5)
|
|
158
|
+
3. Write property-based tests for core functionality
|
|
159
|
+
4. Write integration tests for workflows
|
|
160
|
+
5. Achieve 80% code coverage
|
|
161
|
+
|
|
162
|
+
## Requirements Satisfied
|
|
163
|
+
|
|
164
|
+
- **13.1**: Comprehensive test coverage with unit, integration, and property tests
|
|
165
|
+
- **13.5**: Code coverage reporting with Istanbul/nyc (via Jest)
|
|
166
|
+
- **13.6**: Test scripts configured in package.json
|
|
167
|
+
|
|
168
|
+
## Files Created/Modified
|
|
169
|
+
|
|
170
|
+
### Created:
|
|
171
|
+
- `jest.config.js` - Jest configuration
|
|
172
|
+
- `tests/unit/README.md` - Unit tests documentation
|
|
173
|
+
- `tests/integration/README.md` - Integration tests documentation
|
|
174
|
+
- `tests/property/README.md` - Property tests documentation
|
|
175
|
+
- `tests/utils/testDataGenerator.js` - Sample data generation utilities
|
|
176
|
+
- `tests/utils/testAssertions.js` - Custom assertion utilities
|
|
177
|
+
- `tests/setup.js` - Test environment setup
|
|
178
|
+
- `tests/unit/example.test.js` - Example test
|
|
179
|
+
- `tests/README.md` - Testing infrastructure documentation
|
|
180
|
+
- `TESTING_SETUP.md` - This file
|
|
181
|
+
|
|
182
|
+
### Modified:
|
|
183
|
+
- `package.json` - Added Jest dependency and test scripts
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
testEnvironment: 'node',
|
|
3
|
+
setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
|
|
4
|
+
collectCoverageFrom: [
|
|
5
|
+
'src/**/*.js',
|
|
6
|
+
'!src/index.js',
|
|
7
|
+
'!src/messages/**',
|
|
8
|
+
'!src/dataframe/**',
|
|
9
|
+
'!src/bases/**',
|
|
10
|
+
'!src/features/**',
|
|
11
|
+
'!src/utils/**'
|
|
12
|
+
],
|
|
13
|
+
coverageThreshold: {
|
|
14
|
+
global: {
|
|
15
|
+
branches: 80,
|
|
16
|
+
functions: 80,
|
|
17
|
+
lines: 80,
|
|
18
|
+
statements: 80
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
testMatch: [
|
|
22
|
+
'**/tests/**/*.test.js'
|
|
23
|
+
],
|
|
24
|
+
verbose: true
|
|
25
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pandas",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "An npm package that incorporates minimal features of python pandas.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "jest",
|
|
8
|
+
"test:watch": "jest --watch",
|
|
9
|
+
"test:coverage": "jest --coverage",
|
|
10
|
+
"test:unit": "jest tests/unit",
|
|
11
|
+
"test:integration": "jest tests/integration",
|
|
12
|
+
"test:property": "jest tests/property"
|
|
8
13
|
},
|
|
9
14
|
"repository": {
|
|
10
15
|
"type": "git",
|
|
@@ -22,5 +27,8 @@
|
|
|
22
27
|
"bugs": {
|
|
23
28
|
"url": "https://github.com/hygull/node-pandas/issues"
|
|
24
29
|
},
|
|
25
|
-
"homepage": "https://github.com/hygull/node-pandas#readme"
|
|
30
|
+
"homepage": "https://github.com/hygull/node-pandas#readme",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"jest": "^29.7.0"
|
|
33
|
+
}
|
|
26
34
|
}
|
package/src/bases/CsvBase.js
CHANGED
|
@@ -12,15 +12,6 @@ const CsvBase = {
|
|
|
12
12
|
} else {
|
|
13
13
|
pathDetails = null
|
|
14
14
|
}
|
|
15
|
-
/*
|
|
16
|
-
{
|
|
17
|
-
root: '/',
|
|
18
|
-
dir: '/Users/hygull/Desktop/try',
|
|
19
|
-
base: 'node-pandas.csv',
|
|
20
|
-
ext: '.csv',
|
|
21
|
-
name: 'node-pandas'
|
|
22
|
-
}
|
|
23
|
-
*/
|
|
24
15
|
|
|
25
16
|
if(pathDetails && fs.existsSync(pathDetails)) {
|
|
26
17
|
let csvText = ''
|
|
@@ -29,9 +20,9 @@ const CsvBase = {
|
|
|
29
20
|
|
|
30
21
|
for(let r=0; r < this.rows; ++r) {
|
|
31
22
|
for(let c=0; c < this.cols; ++c) {
|
|
32
|
-
csvText += this.data[r][columns[c]] + ','
|
|
23
|
+
csvText += this.data[r][this.columns[c]] + ','
|
|
33
24
|
}
|
|
34
|
-
csvText = csvText.trim().slice(0, -1) + '\n'
|
|
25
|
+
csvText = csvText.trim().slice(0, -1) + '\n'
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
csvText = csvText.trim()
|
|
@@ -44,11 +35,11 @@ const CsvBase = {
|
|
|
44
35
|
console.log(`CSV file is successfully created at ${outCsvPath}`)
|
|
45
36
|
}
|
|
46
37
|
}
|
|
47
|
-
})
|
|
38
|
+
})
|
|
48
39
|
} else {
|
|
49
40
|
messages.error(`Provided CSV path \`${outCsvPath}\` is invalid`)
|
|
50
41
|
}
|
|
51
42
|
}
|
|
52
43
|
}
|
|
53
44
|
|
|
54
|
-
module.exports = CsvBase
|
|
45
|
+
module.exports = CsvBase
|