Information Security Projects - Stock Price Checker

Tell us what’s happening:

My problem is that the 7th test doesn’t pass. I made sure that NODE_ENV=test is on, and I tested my code and also checked other peoples’ codes on my local host setup(I’m not sure if they work on gitpod or not), although all the functional tests(that I created) pass on mocha. I checked every other solution on the forum(except for really old ones) and didn’t find the answer to my problem. This is what fcc console says: “actual: false

  1. expected: true

  2. message: “expected false to be true”

  3. operator: “strictEqual”

  4. showDiff: true

  5. stack: “AssertionError: expected false to be true\n at eval (eval at #a (https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js:2:255051), :5:10)\n at async #a (https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js:2:255391)\n at async DOMTestEvaluator.handleMessage (https://www.freecodecamp.org/js/test-runner/5.4.1/dom-test-evaluator.js:2:256100)”

  6. [[Prototype]]: Error”.

My server.js code:

'use strict';
require('dotenv').config();
const express     = require('express');
const bodyParser  = require('body-parser');
const cors        = require('cors');
const helmet = require('helmet');
const apiRoutes         = require('./routes/api.js');
const fccTestingRoutes  = require('./routes/fcctesting.js');
const runner            = require('./test-runner');

const app = express();

app.use(helmet());
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'"],
    styleSrc: ["'self'"],
    imgSrc: ["'self'"],
    connectSrc: ["'self'"],
    fontSrc: ["'self'"],
    objectSrc: ["'none'"],
    upgradeInsecureRequests: true
  }
}));
app.use(express.json());

app.use('/public', express.static(process.cwd() + '/public'));

app.use(cors({origin: '*'})); //For FCC testing purposes only

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

//Index page (static HTML)
app.route('/')
  .get(function (req, res) {
    res.sendFile(process.cwd() + '/views/index.html');
  });

//For FCC testing purposes
fccTestingRoutes(app);

//Routing for API 
apiRoutes(app);  

//404 Not Found Middleware
app.use(function(req, res, next) {
  res.status(404)
    .type('text')
    .send('Not Found');
});

//Start our server and tests!
const listener = app.listen(process.env.PORT || 3000, function () {
  console.log('Your app is listening on port ' + listener.address().port);
  if(process.env.NODE_ENV==='test') {
    console.log('Running Tests...');
    setTimeout(function () {
      try {
        runner.run();
      } catch(e) {
        console.log('Tests are not valid:');
        console.error(e);
      }
    }, 3500);
  }
});

module.exports = app; //for testing

My sample.env code:

PORT=3000
NODE_ENV=test

My api.js code:

'use strict';
const fetch = require('node-fetch');
const express = require('express');
const crypto = require('crypto');
const likesDB = {};

function anonymizeIP(ip) {
  if (!ip) return 'unknown';
  return crypto.createHash('sha256').update(ip).digest('hex');
}

async function getRealPrice(symbol) {
  const url = `https://stock-price-checker-proxy.freecodecamp.rocks/v1/stock/${symbol}/quote`;
  const response = await fetch(url);
  const data = await response.json();
  return parseFloat(data.latestPrice);
}

module.exports = function (app) {

  app.route('/api/stock-prices')
    .get(async function (req, res){
      const ip = req.ip || req.headers['x-forwarded-for'];
      const anonymizedIP = anonymizeIP(ip);
      const stock = req.query.stock;
      const like = req.query.like === 'true';

      if (!stock) {
        return res.status(400).json({ error: 'Missing stock parameter' });
      }

      const stocks = Array.isArray(stock) ? stock.map(s => s.toUpperCase()) : [stock.toUpperCase()];
      
      try {
        const stockData = await Promise.all(stocks.map(async (symbol) => {
          const price = await getRealPrice(symbol);
          if (!likesDB[symbol]) {
            likesDB[symbol] = new Set();
          }

          if (like && !likesDB[symbol].has(anonymizedIP)) {
            likesDB[symbol].add(anonymizedIP);
          }

          return {
            stock: symbol,
            price,
            likes: likesDB[symbol].size
          }
        }));

        if (stockData.length === 2) {
          return res.json({
            stockData: stocks.map(symbol => {
              const current = stockData.find(s => s.stock === symbol);
              const other = stockData.find(s => s.stock !== symbol);
              return {
                stock: current.stock,
                price: current.price,
                rel_likes: current.likes - other.likes
              }
            })
          });
          }
          res.json({ stockData: stockData[0] });
      } catch (e) {
        console.error('Error fetching stock data:', e.message);
        res.status(500).json({ error: 'Failed to fetch stock price' });
      }
      
    });
    
};

My functional tests’ code:

const chaiHttp = require('chai-http');
const chai = require('chai');
const assert = chai.assert;
const server = require('../server');

chai.use(chaiHttp);

describe('Functional Tests', function() {
    this.timeout(5000);

    it('Viewing one stock: GET request to /api/stock-prices/', function(done) {
        chai.request(server).keepOpen().get('/api/stock-prices').query({ stock: 'GOOG' })
            .end(function(err, res) {
                assert.equal(res.status, 200);
                assert.property(res.body, 'stockData');
                assert.isObject(res.body.stockData);
                assert.equal(res.body.stockData.stock, 'GOOG');
                assert.isNumber(res.body.stockData.price);
                assert.isNumber(res.body.stockData.likes);
                done();
            });
    })
    
    it('Viewing one stock and liking it: GET request to /api/stock-prices/', function(done) {
        chai.request(server).keepOpen().get('/api/stock-prices').query({ stock: 'GOOG',
                                                               like: true
         })
            .end(function(err, res) {
                assert.equal(res.status, 200);
                assert.property(res.body, 'stockData');
                assert.equal(res.body.stockData.stock, 'GOOG');
                assert.isNumber(res.body.stockData.likes);
                done();
            });
    })

    it('Viewing the same stock and liking it again: GET request to /api/stock-prices/', function(done) {
        chai.request(server).keepOpen().get('/api/stock-prices').query({ stock: 'GOOG',
                                                               like: true
         })
            .end(function(err, res) {
                assert.equal(res.status, 200);
                assert.property(res.body, 'stockData');
                assert.equal(res.body.stockData.stock, 'GOOG');
                done();
            });
    })
    
    it('Viewing two stocks: GET request to /api/stock-prices/', function(done) {
        chai.request(server).keepOpen().get('/api/stock-prices').query({ stock: ['GOOG', 'MSFT'] })
            .end(function(err, res) {
                assert.equal(res.status, 200);
                assert.property(res.body, 'stockData');
                assert.isArray(res.body.stockData);
                assert.lengthOf(res.body.stockData, 2);
                res.body.stockData.forEach(stock => {
                    assert.isString(stock.stock);
                    assert.isNumber(stock.price);
                    assert.isNumber(stock.rel_likes);
                })
                done();
            });
    })
    
    it('Viewing two stocks and liking them: GET request to /api/stock-prices/', function(done) {
        chai.request(server).keepOpen().get('/api/stock-prices').query({ stock: ['GOOG', 'MSFT'],
                                                               like: true
         })
            .end(function(err, res) {
                assert.equal(res.status, 200);
                assert.property(res.body, 'stockData');
                assert.isArray(res.body.stockData);
                assert.lengthOf(res.body.stockData, 2);
                res.body.stockData.forEach(stock => {
                    assert.isString(stock.stock);
                    assert.isNumber(stock.price);
                    assert.isNumber(stock.rel_likes);
                })
                done();
            });
    })
});

Is there an issue with my code? Should I restructure or remake something in it? Is it an issue with the fcc?

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36

Challenge Information:

Information Security Projects - Stock Price Checker

Functional tests to the next project - https://www.freecodecamp.org/learn/information-security/information-security-projects/anonymous-message-board - don’t seem to work as well

what is in your .env file (not the sample.env, that is an other file)? are you using the given boilerplate?

I’m using the given boilerplate. Everything related to node_env and port code is in the sample.env. Should I use another .env file?

you must have a file exactly named .env as it contains secrets it can’t go in the repository, the sample.env file is given as a starting point

1 Like