src/tests/advanced.test.ts   A
last analyzed

Complexity

Total Complexity 4
Complexity/F 0

Size

Lines of Code 176
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 4
eloc 125
mnd 4
bc 4
fnc 0
dl 0
loc 176
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
rs 10
1
import 'async';
2
import 'assert';
3
import 'should';
4
import * as zlib from 'zlib';
5
6
import Sitemapper from '../../lib/assets/sitemapper.js';
7
import { SitemapperResponse } from '../../sitemapper';
8
9
describe('Sitemapper Advanced Tests', function () {
10
  let sitemapper: Sitemapper;
11
12
  beforeEach(() => {
13
    sitemapper = new Sitemapper();
14
  });
15
16
  describe('decompressResponseBody', function () {
17
    it('should correctly decompress gzipped content', async function () {
18
      // Create a sample XML string
19
      const xmlContent =
20
        '<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>https://example.com</loc></url></urlset>';
21
22
      // Compress it with gzip
23
      const compressed = zlib.gzipSync(Buffer.from(xmlContent));
24
25
      // Use the private decompressResponseBody method
26
      const decompressed = await (sitemapper as any).decompressResponseBody(
27
        compressed
28
      );
29
30
      // Check the result
31
      decompressed.toString().should.equal(xmlContent);
32
    });
33
34
    it('should handle decompression errors gracefully', async function () {
35
      // Create invalid gzip content
36
      const invalidGzip = Buffer.from('This is not valid gzip content');
37
38
      try {
39
        // This should throw an error
40
        await (sitemapper as any).decompressResponseBody(invalidGzip);
41
        // If we get here, the test should fail
42
        false.should.be.true(); // Force test to fail if no error is thrown
43
      } catch (error) {
44
        // We should get an error, which is expected
45
        (error as Error).should.be.an.instanceOf(Error);
46
      }
47
    });
48
  });
49
50
  describe('initializeTimeout', function () {
51
    it('should set up a timeout that cancels a request', async function () {
52
      // Create a mock requester with a cancel method
53
      const mockRequester = {
54
        cancel: function () {
55
          this.canceled = true;
56
        },
57
        canceled: false,
58
      };
59
60
      // Set a very short timeout
61
      sitemapper.timeout = 1;
62
63
      // Call initializeTimeout
64
      (sitemapper as any).initializeTimeout(
65
        'https://example.com/timeout-test',
66
        mockRequester
67
      );
68
69
      // Wait for the timeout to trigger
70
      await new Promise((resolve) => setTimeout(resolve, 10));
71
72
      // Check if cancel was called
73
      mockRequester.canceled.should.be.true();
74
75
      // Clean up
76
      clearTimeout(
77
        (sitemapper as any).timeoutTable['https://example.com/timeout-test']
78
      );
79
    });
80
  });
81
82
  describe('parse error handling', function () {
83
    it('should handle network errors during parse', async function () {
84
      // Store original fetch implementation
85
      const originalFetch = global.fetch;
86
87
      // Mock fetch to throw a network error
88
      (global as any).fetch = () => {
89
        const error = new Error('HTTP Error occurred');
90
        error.name = 'HTTPError';
91
        throw error;
92
      };
93
94
      try {
95
        // Try to parse a URL
96
        const result = await (sitemapper as any).parse(
97
          'https://example.com/error-test'
98
        );
99
100
        // Check the result
101
        result.should.have.property('error').which.is.a.String();
102
        result.should.have.property('data').which.is.an.Object();
103
        (result.data as any).should.have
104
          .property('name')
105
          .which.is.equal('HTTPError');
106
      } finally {
107
        // Restore the original fetch
108
        (global as any).fetch = originalFetch;
109
      }
110
    });
111
  });
112
113
  describe('fetch with multiple sitemaps', function () {
114
    it('should handle errors in some child sitemaps while succeeding with others', async function () {
115
      this.timeout(10000);
116
117
      // Create a mock parse method that returns a sitemapindex with mixed results
118
      const originalParse = sitemapper.parse;
119
      const originalCrawl = sitemapper.crawl;
120
121
      // First call to parse returns sitemapindex with multiple sitemaps
122
      let parseCallCount = 0;
123
      sitemapper.parse = async () => {
124
        parseCallCount++;
125
126
        if (parseCallCount === 1) {
127
          // First call returns a sitemapindex with two sitemaps
128
          return {
129
            data: {
130
              sitemapindex: {
131
                sitemap: [
132
                  { loc: 'https://example.com/good-sitemap.xml' },
133
                  { loc: 'https://example.com/bad-sitemap.xml' },
134
                ],
135
              },
136
            },
137
          };
138
        } else if (parseCallCount === 2) {
139
          // Second call (for good-sitemap) returns urlset
140
          return {
141
            data: {
142
              urlset: {
143
                url: [
144
                  { loc: 'https://example.com/page1' },
145
                  { loc: 'https://example.com/page2' },
146
                ],
147
              },
148
            },
149
          };
150
        } else {
151
          // Third call (for bad-sitemap) returns error
152
          return {
153
            error: 'Error occurred: ParseError',
154
            data: { name: 'ParseError' },
155
          };
156
        }
157
      };
158
159
      // Call fetch which will use our mocked methods
160
      const result = await sitemapper.fetch(
161
        'https://example.com/root-sitemap.xml'
162
      );
163
164
      // Check the result
165
      result.should.have.property('sites').which.is.an.Array();
166
      result.should.have.property('errors').which.is.an.Array();
167
      result.sites.length.should.equal(2);
168
      result.errors.length.should.equal(1);
169
170
      // Restore original methods
171
      sitemapper.parse = originalParse;
172
      sitemapper.crawl = originalCrawl;
173
    });
174
  });
175
});
176